1. PREPARE

Our first SNA case study is guided by the work of Matthew Pittinsky and Brian V. Carolan (2008), which employed a social network perspective to examine teachers perceptions of student friendships agreed with their own. Sadly, this excellent study did not include any visual depictions comparing student and teacher perceived friendship networks, but we are going to fix that!

Our primary aim for this case study is to gain some hands-on experience with essential R packages and functions for preparing network data for analysis and creating a simple network sociogram to help describe visually what our network “looks like.” Specifically, this case study will cover the following topics pertaining to each data-intensive workflow process (Krumm, Means, and Bienkowski 2018):

  1. Prepare: Prior to analysis, we’ll take a look at the context from which our data came, formulate some research questions, and get introduced the {tidygraph} and {ggraph} packages for analyzing and visualizing relational data.

  2. Wrangle: In the wrangling section of our case study, we will learn some basic techniques for manipulating, cleaning, transforming, and merging network data.

  3. Explore: With our network data tidied, we learn to calculate some key network measures and to illustrate some of these stats through network visualization.

  4. Model: We conclude our analysis by introducing community detection algorithms for identifying groups and revisiting sentiment about the common core.

  5. Communicate: We develop a polished sociogram to highlight key findings.

1a. Review the Research

Pittinsky, M., & Carolan, B. V. (2008). Behavioral versus cognitive classroom friendship networks. Social Psychology of Education11(2), 133-147.

Abstract

Researchers of social networks commonly distinguish between “behavioral” and “cognitive” social structure. In a school context, for example, a teacher’s perceptions of student friendship ties, not necessarily actual friendship relations, may influence teacher behavior. Revisiting early work in the field of sociometry, this study assesses the level of agreement between teacher perceptions and student reports of within-classroom friendship ties. Using data from one middle school teacher and four classes of students, the study explores new ground by assessing agreement over time and across classroom social contexts, with the teacher-perceiver held constant. While the teacher’s perceptions and students’ reports were statistically similar, 11–29% of possible ties did not match. In particular, students reported significantly more reciprocated friendship ties than the teacher perceived. Interestingly, the observed level of agreement varied across classes and generally increased over time. This study further demonstrates that significant error can be introduced by conflating teacher per- ceptions and student reports. Findings reinforce the importance of treating behavioral and cognitive classroom friendship networks as distinct, and analyzing social structure data that are carefully aligned with the social process hypothesized.

Research Questions

The central question guiding this investigation was:

Do student reports agree with teacher perceptions when it comes to classroom friendship ties and with what consequences for commonly used social network measures?

We will be using this question to guide our own analysis of the classroom friendships reported by teachers. Specifically, we will use the first part of this question to guide our analysis and develop two sociograms to help visually compare similarities and differences between teacher and student reported classroom friendships.

Data Collection

To measure the level of agreement between student and teacher reports of classroom student friendships, sociometric data were collected from each student in all four classes and the teacher provided similar reports on all students. To collect student reports of friendships, students were given a class roster and asked to describe their relationship with each student in the class. Choices included best friend, friend, know-like, know, know-dislike, strongly dislike, and do not know. In the terminology of network analysis, these sociometric data are “valued” (degrees of friendship, not just yes or no) and “directed” (friendship nominations were not presumed to be reciprocal). Data were collected in the autumn and spring. All “best friend” and “friend” choices are coded as ‘1’ (friend), while all other choices are coded as ‘0’ (not friend). The teacher’s reports of students’ friendships were generated in a similar manner.

Analyses

To assess agreement between perceived friendship by the teacher and students, QAP (quadratic assignment procedure) correlations for each class’s two matrices (teacher and student generated) were analyzed in the autumn andspring. A QAP correlation is used to calculate the degree of association between two sets of relations; it tests whether the probability of dyad overlap in the teacher matrix is correlated with the probability of dyad overlap in the student matrix. It does so by running a large number of simulations. These simulations generate random matrices with sizes and value distributions based on the original two matrices being tested. It then computes an average level of correlation between the matrices that would be expected at random. Similarly, it calculates the probability that the observed degree of correlation between two matrices would be as large or as small as that observed based on the range of correlations generated in the random permutations, with an associated significance statistic.

Key Findings

As reported by Pittinsky and Carolan (2008) in their findings section:

While the teacher’s perceptions and students’ reports were statistically similar, 11–29% of possible ties did not match. In particular, students reported significantly more reciprocated friendship ties than the teacher perceived.

👉 Your Turn

Take a look at the paper in our essential readings repository on GitHub and highlight one or two findings and/or conclusions you found especially interesting.

1b. Identify a Question(s)

Recall from above that the central question guiding the #COMMONCORE Project was:

How are social media-enabled social networks changing the discourse in American politics that produces and sustains education policy?

For Unit 4, we are going to focus our questions on something a bit less ambitious but inspired by this work:

  1. Who are the transmitters, transceivers, and transcenders in our Common Core Twitter network?
  2. What subgroups, or factions, exist in our network?
  3. Which actors in our network tend to be more opposed to the Common Core?

To address the last question, we’ll revisit our techniques we learned from our Unit 3 VADER sentiment analysis.

👉 Your Turn

Based on what you know about networks and the context so far, what other research question(s) might ask we ask in this context that a social network perspective might be able to answer?

In the space below, type a brief response to the following questions:

  • YOUR RESPONSE HERE

1c. Load Packages

As highlighted in Chapter 6 of Data Science in Education Using R (DSIEUR), one of the first steps of every workflow should be to set up your “Project” within RStudio. Recall that:

A Project is the home for all of the files, images, reports, and code that are used in any given project

Since we are working from an R project cloned from GitHub, a Project has already been set up for you as indicated by the .Rproj file in your main directory in the Files pane. Instead, we will focus on getting our project set up withe the requisite packages we’ll need for analysis.

Packages, or sometimes called libraries, are shareable collections of R code that can contain functions, data, and/or documentation and extend the functionality of R. You can always check to see which packages have already been installed and loaded into RStudio Cloud by looking at the the Files, Plots, & Packages Pane in the lower right hand corner.

tidyverse 📦

One package that we’ll be using extensively is {tidyverse}. Recall from earlier tutorials that the {tidyverse} package is actually a collection of R packages designed for reading, wrangling, and exploring data and which all share an underlying design philosophy, grammar, and data structures. This shared features are sometimes “tidy data principles.”

Click the green arrow in the right corner of the “code chunk” that follows to load the {tidyverse} library as well as the {here} package introduced in previous labs.

library(tidyverse)

Don’t worry if you saw a number of messages: those probably mean that the tidyverse loaded just fine. Any conflicts you may have seen mean that functions in these packages you loaded have the same name as functions in other packages and R will default to function from the last loaded package unless

Next, we will introduce two new packages extend the tidyverse suite of packages and that we will use throughout SNA Learning Labs 1-4.

New Packages

tidygraph 📦

The {tidygraph} package is a huge package that exports 280 different functions and methods, including access to almost all of the dplyr verbs plus a few more, developed for use with relational data. While network data itself is not tidy, it can be envisioned as two tidy tables, one for node data and one for edge data.

The {tidygraph} package provides a way to switch between the two tables and uses dplyr verbs to manipulate them. Furthermore it provides access to a lot of graph algorithms with return values that facilitate their use in a tidy workflow.

ggraph 📦

Created by the same developer as {tidygraph}, {ggraph} – pronounced gg-raph or g-giraffe hence the logo – is an extension of {ggplot} aimed at supporting relational data structures such as networks, graphs, and trees. Both packages are more modern and widely adopted approaches data visualization in R.

While ggraph builds upon the foundation of ggplot and its API, it comes with its own self-contained set of geoms, facets, etc., as well as adding the concept of layouts to the grammar of graphics, i.e. the “gg” in ggplot and ggraph.

readxl 📦

The {readxl} package makes it easy to get data out of Excel and into R. Compared to many of the existing packages (e.g. gdata, xlsx, xlsReadWrite) readxl has no external dependencies, so it’s easy to install and use on all operating systems. It is designed to work with tabular data.

Since one of our data wrangling steps in the next section is importing network matrices stored in excel files, this package will come in handy.

👉 Your Turn

Use the code chunk below load the {tidygraph} and {ggraph} packages:

# YOUR CODE HERE
library(tidygraph)
library(ggraph)
library(readxl)

2. WRANGLE

In general, data wrangling involves some combination of cleaning, reshaping, transforming, and merging data (Wickham and Grolemund 2016). As highlighted in Estrellado et al. (2020), wrangling network data can be even more challenging than other data sources since network data often includes variables about both individuals and their relationships.

For our data wrangling in lab, we’re keeping it simple since working with relational data is a bit of a departure from our working with rectangular data frames. Our primary goals for Lab 1 are learning how to:

  1. Import Data. In this section, we learn about the read_csv() function for importing a data stored in a format in a unique two common formats for storing network data: edgelists and nodelists.

  2. Create a Network Object. Before we can create our sociogram, we’ll first need to convert our data frames into special data format, an R network object, for working with relational data.

2a. Import Data

One of our primary goals for this case study to is create . To do so, we’ll need to import two Excel files originally obtained from the Social Network Analysis and Education companion site. Both files contain edges stored as a square matrix (more on this later) for the first and third year of a study examining the impact of national reform efforts.

These files are included in the lab-1/data folder of your R Studio project. A description of each file from the companion website is copied below along with a link to the original file:

  1. 99472_ds3.xlsxThis adjacency matrix consists of student-reported friendship relations among 27 students in one class in the fall semester. These data are directed and unweighted; a friendship tie is present if the student reported that another was either a best friend or friend.

  2. 99472_ds5.xlsxThis adjacency matrix consists of the teacher-reported friendship relations among 27 students in one class in the fall semester. These data are directed and unweighted; a friendship tie is present if the teacher reported that students were either a best friend or friend.

Recall from above that our relations, or edges, are stored as a valued adjacency matrix in which columns and rows consist of the same actors and each cell contains information about the tie between each pair of actors. In our case, the tie is a directed and valued “arc” where the value indicates the frequency of collaboration.

Let’s use the read_excel() function to import the student-reported-friends.xlsx file, add an argument setting the column names to FALSE since our file is a simple matrix with no header or column names, and assign the matrix to a variable named student_friends:

R Studio Tip: Type ?read_excel into the console and check the arguments section to examine the different arguments that can be used with this function.

student_friends <- read_excel("data/student-reported-friends.xlsx", 
                              col_names = FALSE)

Before importing our teacher reported friendship file, let’s quickly inspect the student_friends R object we just imported to see what we’ll be working with.

student_friends
## # A tibble: 27 × 27
##     ...1  ...2  ...3  ...4  ...5  ...6  ...7  ...8  ...9 ...10 ...11 ...12 ...13
##    <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1     0     1     0     1     1     1     1     1     1     0     0     1     0
##  2     1     0     0     0     1     0     0     0     0     1     1     0     0
##  3     1     0     0     1     0     0     0     1     0     1     0     0     0
##  4     1     0     0     0     0     0     0     0     0     0     0     1     0
##  5     1     1     0     1     0     1     1     1     1     0     1     1     1
##  6     1     0     0     0     1     0     0     0     1     0     1     1     1
##  7     1     0     1     1     0     0     0     0     1     0     0     0     1
##  8     1     0     1     1     1     0     1     0     1     1     1     0     1
##  9     1     0     0     0     0     1     1     0     0     0     1     0     1
## 10     1     1     1     1     1     0     1     1     0     0     1     1     1
## # … with 17 more rows, and 14 more variables: ...14 <dbl>, ...15 <dbl>,
## #   ...16 <dbl>, ...17 <dbl>, ...18 <dbl>, ...19 <dbl>, ...20 <dbl>,
## #   ...21 <dbl>, ...22 <dbl>, ...23 <dbl>, ...24 <dbl>, ...25 <dbl>,
## #   ...26 <dbl>, ...27 <dbl>

As you can see, we have a 27 x 27 “tibble” or data table representing our collaboration ties. Unfortunately, this data is stored in such a simple format, we have no way to easily identify who is friends who since our data is missing names or some kind of identifier for students in our network.

R has packages for creating random names to help anonymize data, but to keep things simple, we’ll just assign the numbers 1-27 as names for our rows and columns.

rownames(student_friends) <- 1:27

colnames(student_friends) <- 1:27

You may have seen a warning stating: Setting row names on a tibble is deprecated. You can ignore that for now but it’s basically telling us these functions are old we we need to use newer function or our code will some day stop working.

Again, let quickly inspect our student_friends data table to see if this worked:

student_friends
## # A tibble: 27 × 27
##      `1`   `2`   `3`   `4`   `5`   `6`   `7`   `8`   `9`  `10`  `11`  `12`  `13`
##  * <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1     0     1     0     1     1     1     1     1     1     0     0     1     0
##  2     1     0     0     0     1     0     0     0     0     1     1     0     0
##  3     1     0     0     1     0     0     0     1     0     1     0     0     0
##  4     1     0     0     0     0     0     0     0     0     0     0     1     0
##  5     1     1     0     1     0     1     1     1     1     0     1     1     1
##  6     1     0     0     0     1     0     0     0     1     0     1     1     1
##  7     1     0     1     1     0     0     0     0     1     0     0     0     1
##  8     1     0     1     1     1     0     1     0     1     1     1     0     1
##  9     1     0     0     0     0     1     1     0     0     0     1     0     1
## 10     1     1     1     1     1     0     1     1     0     0     1     1     1
## # … with 17 more rows, and 14 more variables: `14` <dbl>, `15` <dbl>,
## #   `16` <dbl>, `17` <dbl>, `18` <dbl>, `19` <dbl>, `20` <dbl>, `21` <dbl>,
## #   `22` <dbl>, `23` <dbl>, `24` <dbl>, `25` <dbl>, `26` <dbl>, `27` <dbl>

Much better! Now we can see that student 1 indicated that student 2 is their friend, an student 2 indicated that student 1 is their friend, so we can say that this friendship is “reciprocated.”

👉 Your Turn

Complete the code chunk below to import the student-reported-friends.xlsx file,

# YOUR CODE HERE
teacher_friends <- read_excel("data/teacher-reported-friends.xlsx", 
                              col_names = FALSE)

rownames(teacher_friends) <- 1:27

colnames(teacher_friends) <- 1:27

teacher_friends
## # A tibble: 27 × 27
##      `1`   `2`   `3`   `4`   `5`   `6`   `7`   `8`   `9`  `10`  `11`  `12`  `13`
##  * <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1     0     0     0     1     0     0     0     0     0     0     0     1     0
##  2     0     0     1     0     0     0     0     1     0     1     0     0     0
##  3     0     1     0     0     0     0     0     1     0     1     0     0     0
##  4     0     0     0     0     0     0     0     0     0     0     0     0     0
##  5     1     0     0     0     0     0     0     0     0     0     0     1     1
##  6     0     0     0     0     0     0     0     0     0     0     0     0     1
##  7     0     0     0     0     0     0     0     0     0     0     0     0     1
##  8     0     1     1     0     0     0     0     0     0     1     0     0     0
##  9     0     0     0     0     0     0     0     0     0     0     1     0     0
## 10     0     1     1     0     0     0     0     1     0     0     0     0     0
## # … with 17 more rows, and 14 more variables: `14` <dbl>, `15` <dbl>,
## #   `16` <dbl>, `17` <dbl>, `18` <dbl>, `19` <dbl>, `20` <dbl>, `21` <dbl>,
## #   `22` <dbl>, `23` <dbl>, `24` <dbl>, `25` <dbl>, `26` <dbl>, `27` <dbl>

2b. Make a Tidy Graph

Before we can begin exploring our data through through network visualization, we must first restructure our “tibble” into a formal matrix object and then convert to a network class R object required by the {tidygraph} and {ggraph} packages.

Convert to Matrix

Now that we have names included for our rows and columns, we need to convert our data table, or tibble, to a formal matrix class object. To do so is relatively simple using the as.matrix() function built into R.

student_matrix <- as.matrix(student_friends)

The word “class” and “object” have been used quite a bit in this case-study and warrant a brief explanation. Classes and objects are basic concepts of Object-Oriented Programming environments like R. An object is simply a data structure that has some methods and attributes. Everything in R is essentially an object. A class is just a blueprint or a sketch of these objects. It represents the set of properties or methods that are common to all objects of one type.

Let’s use the class() function on the student_friends and student_matrix to see the types of objects we just created:

class(student_friends)
## [1] "tbl_df"     "tbl"        "data.frame"
class(student_matrix)
## [1] "matrix" "array"

Great! We can now see that our student_matrix is formally an object of the “matrix” class.

Convert to Graph Object

Our final step before we’re able to begin exploring our data is to convert our matrix to a network object recognized by the {tidygraph} and {ggraph} packages. The as_tbl_graph() function can easily convert relational data from all common network data formats such as matrices, network, phylo, dendrogram, data.tree, graph, etc. 

Run the following code to convert our matrix to directed network graph and save as a new object called student_network: and include the argument directed = TRUE in our as_tbl_graph() function since our network is directed.

student_network <- as_tbl_graph(student_matrix, directed = TRUE)

Now let’s take a quick look at our new student_network object:

student_network
## # A tbl_graph: 27 nodes and 203 edges
## #
## # A directed simple graph with 2 components
## #
## # Node Data: 27 × 1 (active)
##   name 
##   <chr>
## 1 1    
## 2 2    
## 3 3    
## 4 4    
## 5 5    
## 6 6    
## # … with 21 more rows
## #
## # Edge Data: 203 × 3
##    from    to weight
##   <int> <int>  <dbl>
## 1     1     2      1
## 2     1     4      1
## 3     1     5      1
## # … with 200 more rows

As you can see, our student_network object provides a range of information about out network including network size, type, number of components, and a preview of the node and edge lists that it created. The node and edge lists are treated just like a typical data frame and can now be used with other tidyverse packages and functions to create new actor-level network variables like degree, reciprocity, and centrality measures.

What is an edge list?

We’ll learn more about edgelists in Lab 3, but the edgelist format is very commonly used in network analysis but is slightly different than other formats you have likely worked with before. Specifically, the values in the first two columns of each row represent a dyad, or tie between two nodes in a network. An edge-list can also contain other information regarding the strength, duration, or frequency of the relationship, sometime called weight, in addition to other “edge attributes.”

In directed networks like ours, the first column indicates that student 1 indicated students 2, 4, and 5 are friends. Since our network is unweighted, the 1 for “weight” just indicated that a friendship was present.

👉 Your Turn

Complete the code chunk below to convert your teacher_friends object first to a matrix and then to a network object:

# YOUR CODE HERE
teacher_matrix <- as.matrix(teacher_friends)

teacher_network <- as_tbl_graph(teacher_matrix, directed = TRUE)

teacher_network
## # A tbl_graph: 27 nodes and 69 edges
## #
## # A directed simple graph with 6 components
## #
## # Node Data: 27 × 1 (active)
##   name 
##   <chr>
## 1 1    
## 2 2    
## 3 3    
## 4 4    
## 5 5    
## 6 6    
## # … with 21 more rows
## #
## # Edge Data: 69 × 3
##    from    to weight
##   <int> <int>  <dbl>
## 1     1     4      1
## 2     1    12      1
## 3     1    27      1
## # … with 66 more rows

Now answer the questions that following questions:

  1. How many students are in our network?
    • YOUR RESPONSE HERE
  2. Who reported more friendships, teachers or students? How do you know?
    • YOUR RESPONSE HERE

3. EXPLORE

As noted in in our course readings, exploratory data analysis involves the processes of describing your data (such as by calculating the means and standard deviations of numeric variables, or counting the frequency of categorical variables) and, often, visualizing your data prior to modeling.

In Section 3, we use the {tidygraph} package for retrieving network descriptives and introduce the {ggraph} package to create a network visualization to help illustrate these metrics. Specifically, in this section we’ll learn to:

  1. Plot Basics. We focus primarily on actors and edges in this walkthrough, including the edges wights we added in the previous section as well as node degree, and import and fairly intuitive measure of centrality.

  2. Adding Nodes.

  3. Adding Edges. Finally, we wrap up the explore phases by learning to plot a network and tweak key elements like the size, shape, and position of nodes and edges to better at communicating key findings.

One of the defining characteristics of the social network perspective is its use of graphic imagery to represent actors and their relations with one another. To emphasize this point, Carolan (2014) reported that:

The visualization of social networks has been a core practice since its foundation more than 100 years ago and remains a hallmark of contemporary social network analysis. 

Network visualization can be used for a variety of purposes, ranging from highlighting key actors to even serving as works of art.

This excellent figure from Katya Ognyanova’s also excellent tutorial on Static and Dynamic Network Visualization with R helps illustrate the variety of goals a good network visualization can accomplish:

3a. Simple Sociograms

These visual representations of the actors and their relations, i.e. the network, are called a sociogram. Actors who are most central to the network, such as those with higher node degrees, are usually placed in the center of the sociogram and their ties are placed near them. As we’ll see in just a bit, those two actors with hundreds of ties will be placed by most graph layout algorithms in the center of the graph.

The plot() function from R’s built in {graphics} package can be used to make a wide range of graphs, including sociograms, but as you’ll see it’s a bit lacking and is limited limited in the level of customization allowed.

In the code chunk below, use the plot() function with your ccss_network object to see what the basic plot function produces:

plot(student_network)

Not super great. In fact, it’s visualizations like these that give sociograms the unflattering nickname of “hair ball” plots!

If this had been a smaller network this might have been a little more useful but one important insight is that we have already identified an “isolate” in our network, that is a student who neither named others as a friend or was named by others as a friend.

Fortunately, the {ggraph} package includes a plethora of plotting parameters for graph layouts, edges and nodes to improve the visual design of network graphs.

Let’s first take a quick look the auto_graph() function for making quick and simple sociograms.

autograph(student_network)

A little better, but also lacking in many important ways. Like the plot() function, it does allow some small degree of customization, but is still rather limited and best use for very quick sociograms to get a quick feel for the data.

Run the following code chunk to see some additional arguments you can add to the autograph() function:

autograph(student_network,
          node_size = local_size(),
          node_label = name,
          node_colour = local_size())

👉 Your Turn

Use the code chunk below to try out these simple sociogram functions on your teacher_network object you created above:

# YOUR CODE HERE
plot(teacher_network)

autograph(teacher_network,
          node_size = local_size(),
          node_colour = local_size())

3b. Sophisticated Sociograms

One thing to keep in mind when building a network viz with {ggraph}, is that just like it’s ggplot() counterpart, the ggraph() function is the first function required and takes care of setting up the plot object along with creating the layout for the plot based on the network object and the layout specification provided.

Let’s first pass our student_network object to ggraph() and see what happens.

ggraph(student_network)

Wow, that was unimpressive. But don’t worry, just like the ggplot() function, this didn’t produce much on it’s own. All that the ggraph() function does is set up the network object to make a sociogram, and creates a layout for our network, in this case using the default “stress” layout.

Add Nodes

Very similar to how ggplot() uses the + operator to “layer” functions together to progressively build more sophisticated graphs, ggraph use the + operator progressively build a sociogram.

To add our nodes, we’ll added the geom_node_point() function. Again, just like with {ggplot2}, the “geom” in the geom_non_point() functions stands for “Geometric elements”, or geoms for short, and represents what you actually see in the plot.

👉 Your Turn

Now “add” the geom_node_point() function to our code using the + operator:

ggraph(student_network) + 
  geom_node_point() 

Well, at least we have our nodes now! But the default “stress” layout for our sociogram is not so great. Let’s fix that.

Add Layout

One of the major advances in visualization since the first hand-drawn sociograms developed by Jacob Moreno (1934) to represent relations among children in school is the use of software and algorithms to automatically layout networks on a grid.

There are may different layout methods, but we’ll start with the Fruchterman-Reingold (FR) layout, which is one of the most used layout algorithms for network visualization. These types of force-directed algorithms generally work well with large networks and try to layout graphs in “an aesthetically-pleasing way” by making edges roughly equal in length and minimizing overlap.

Let’s go ahead and include the layout argument, which in addition to including its own unique layouts, can incorporate layouts form {igraph} package like fr for the Fruchterman-Reingold (FR) layout:

ggraph(student_network, layout = "fr") +
  geom_node_point()

That’s not much better so let’s stick with the “stress” layout for now. Feel free to try out some other ggraph layout methods if you like, however.

Tweak Nodes

Also like {ggplot2}, geoms can include aesthetics, or aes for short, such as alpha for transparency, as well as color, shape and size.

Let’s now add some “aesthetics” to our points by including the aes() function and arguments such as size = and color =, which set using local_size() function to help highlight the number of friends students have:

ggraph(student_network, layout = "stress") + 
geom_node_point(aes(size = local_size(),
                    color = local_size()))

We can easily see that the number of friends ranges from 5 to 20, with the exception of one “isolated” student we identified earlier who is not connected to any other students in the network.

Let’s fix that by adding another layer with some node text and labels. Since node labels are a geometric element, we can apply aesthetics to them as well, like color and size. Let’s also include the repel = argument that when set to TRUE will avoid overlapping text.

ggraph(student_network, layout = "stress") + 
  geom_node_point(aes(size = local_size(),
                      color = local_size())) +
  geom_node_text(aes(label = name,
                     size = local_size()), # note we can treat this like a number
                 repel=TRUE)

Add Edges

Now, let’s literally connect the dots and add some edges using the geom_edge_link() function.

ggraph(student_network, layout = "stress") + 
  geom_node_point(aes(size = local_size(),
                      color = local_size())) +
  geom_node_text(aes(label = name),
                 repel=TRUE) +
  geom_edge_link()

Ack! Without some adjustment, the edges make it really difficult to see the nodes. Fortunately, you can also adjust the edges just like we did to the nodes above: Let’s now include the following arguments:

  • arrow = to include some arrows 1mm in length

  • end_cap = around each node to keep arrows from overlapping the them, and to

  • alpha = .2 set the transparency of our edges so our edges fade more into the background and help keep the focus on our nodes:

ggraph(student_network, layout = "stress") + 
  geom_node_point(aes(size = local_size(),
                      color = local_size())) +
  geom_node_text(aes(label = name),
                 repel=TRUE) +
  geom_edge_link(arrow = arrow(length = unit(1, 'mm')), 
                 end_cap = circle(3, 'mm'),
                 alpha = .2)

Add a Theme

Finally, let’s add a theme, which controls the finer points of display, like the font size and background color. The theme_graph() function add a theme specially tuned for graph visualizations. This function removes redundant elements in order to put focus on the data and if you type ?theme_graph in the console you will get a sense of the level of fine tuning you can do if desired.

Let’s add theme_graph() to our sociogram, remove the legends since they are not especially useful, and call it good for now:

ggraph(student_network, layout = "stress") + 
  geom_node_point(aes(size = local_size(),
                      color = local_size())) +
  geom_node_text(aes(label = name),
                 repel=TRUE) +
  geom_edge_link(arrow = arrow(length = unit(1, 'mm')), 
                 end_cap = circle(3, 'mm'),
                 alpha = .2) +
  theme_graph()

Much better!

Note: If you’re having difficulty seeing the sociogram in the small R Markdown code chunk, you can copy and paste the code in the console and it will show in the Viewer pan and then you can enlarge and even save as an image file.

👉 Your Turn

Now that you have a sense of how the {ggraph} package works to build network graphs, use the code chunk below and try building sophisticated sociogram for the teacher_network object that you created above.

There are no right or wrong answers, just have some fun trying out different options for graph layouts, edges and nodes and see if you can build something that is visually pleasing to you.

ggraph(teacher_network, layout = "fr") + 
  geom_node_point(aes(size = local_size(),
                      color = local_size())) +
  geom_node_text(aes(label = name),
                 repel=TRUE) +
  geom_edge_link(arrow = arrow(length = unit(1, 'mm')), 
                 end_cap = circle(3, 'mm'),
                 alpha = .2) +
  theme_graph()

Congrats! You made it to the end of the EXPLORE section!


4. MODEL

As highlighted in Chapter 3 of Data Science in Education Using R, the Model step of the data science process entails “using statistical models, from simple to complex, to understand trends and patterns in the data.” We will not explore the use of models for SNA until Lab 4, but recall from the PREPARE section that to assess agreement between perceived friendships by the teacher and students, (Pittinsky and Carolan 2008) note that:

The QAP (quadratic assignment procedure) [is] used to calculate the degree of association between two sets of relations and tests whether the probability of dyad overlap in the teacher matrix is correlated with the probability of dyad overlap in the student matrix. It does so by running a large number of simulations. These simulations generate random matrices with sizes and value distributions based on the original two matrices being tested.

We will learn more about the QAP and other models for statistical inference when working with relational data in Learning Lab 4.


5. COMMUNICATE

Our goal is to distill the analysis from above into a simple “data product” designed to illustrate key findings about changes in the collaboration network over time. For the purposes of this task, imagine that your audience consists of teachers and school leaders who have limited background in SNA and adapt the following steps accordingly:

  1. Select. Select our sociogram from above, or create a entirely new sociogram if so motivated, that you think would be interesting or relevant for the target audience and that helps answer our research question.

  2. Polish. Create a visually attractive sociogram to help illustrate similarities and differences in classroom friendships reported by teachers and students.

  3. Narrate. Write a brief narrative to accompany your visualization and/or table that includes the following:

    • The question or questions guiding the analysis;

    • The conclusions you’ve reached based on our findings;

    • How your audience might use this information;

    • How you might revisit or improve upon this analysis in the future.

👉 Your Turn ⤵

Use the code chunk below create a polished table and/or visualization(s) and write a brief narrative in the space that follows.

Data Visualization or Table

# YOUR CODE HERE

Narrative

NARRATIVE GOES HERE…

🧶 Knit & Check ✅

Congratulations - you’ve completed the Lab 4 case study! One final step is to “Knit” your document by clicking the drop down arrow next to the ball of yarn in the menu bar an that the top of this markdown file, and then selecting “Knit top HTML” or another preferred output format. This will do two things: 1) it will check through all your code for any errors, 2) it will created a file in your directory that you can use to share you work through GitHub Pages, RPubs, or any other preferred means.

References

Carolan, Brian. 2014. “Social Network Analysis and Education: Theory, Methods & Applications.” https://doi.org/10.4135/9781452270104.
Estrellado, Ryan A., Emily A. Freer, Jesse Mostipak, Joshua M. Rosenberg, and Isabella C. Velásquez. 2020. Data Science in Education Using r. Routledge. https://doi.org/10.4324/9780367822842.
Krumm, Andrew, Barbara Means, and Marie Bienkowski. 2018. Learning Analytics Goes to School. Routledge. https://doi.org/10.4324/9781315650722.
Pittinsky, Matthew, and Brian V Carolan. 2008. “Behavioral Versus Cognitive Classroom Friendship Networks.” Social Psychology of Education 11 (2): 133–47.
Wickham, Hadley, and Garrett Grolemund. 2016. R for Data Science: Import, Tidy, Transform, Visualize, and Model Data. " O’Reilly Media, Inc.". https://r4ds.had.co.nz.
LS0tCnRpdGxlOiAiV2hvJ3MgRnJpZW5kcyB3aXRoIFdobyBpbiBNaWRkbGUgU2Nob29sIgpzdWJ0aXRsZTogIkxBU0VSIEluc3RpdHV0ZSBMZWFybmluZyBMYWIgMSBDYXNlIFN0dWR5IgphdXRob3I6ICJEci4gU2hhdW4gS2VsbG9nZyIKZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCclQiAlZSwgJVknKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogVFJVRQplZGl0b3Jfb3B0aW9uczoKICBtYXJrZG93bjoKICAgIHdyYXA6IDcyCmJpYmxpb2dyYXBoeTogcmVmZXJlbmNlcy5iaWIKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSkKYGBgCgojIyAxLiBQUkVQQVJFCgpPdXIgZmlyc3QgU05BIGNhc2Ugc3R1ZHkgaXMgZ3VpZGVkIGJ5IHRoZSB3b3JrIG9mIE1hdHRoZXcgUGl0dGluc2t5IGFuZApCcmlhbiBWLiBDYXJvbGFuICgyMDA4KSwgd2hpY2ggZW1wbG95ZWQgYSBzb2NpYWwgbmV0d29yayBwZXJzcGVjdGl2ZSB0bwpleGFtaW5lIHRlYWNoZXJzIHBlcmNlcHRpb25zIG9mIHN0dWRlbnQgZnJpZW5kc2hpcHMgYWdyZWVkIHdpdGggdGhlaXIKb3duLiBTYWRseSwgdGhpcyBleGNlbGxlbnQgc3R1ZHkgZGlkIG5vdCBpbmNsdWRlIGFueSB2aXN1YWwgZGVwaWN0aW9ucwpjb21wYXJpbmcgc3R1ZGVudCBhbmQgdGVhY2hlciBwZXJjZWl2ZWQgZnJpZW5kc2hpcCBuZXR3b3JrcywgYnV0IHdlIGFyZQpnb2luZyB0byBmaXggdGhhdCEKCk91ciBwcmltYXJ5IGFpbSBmb3IgdGhpcyBjYXNlIHN0dWR5IGlzIHRvIGdhaW4gc29tZSBoYW5kcy1vbiBleHBlcmllbmNlCndpdGggZXNzZW50aWFsIFIgcGFja2FnZXMgYW5kIGZ1bmN0aW9ucyBmb3IgcHJlcGFyaW5nIG5ldHdvcmsgZGF0YSBmb3IKYW5hbHlzaXMgYW5kIGNyZWF0aW5nIGEgc2ltcGxlIG5ldHdvcmsgc29jaW9ncmFtIHRvIGhlbHAgZGVzY3JpYmUKdmlzdWFsbHkgd2hhdCBvdXIgbmV0d29yayAibG9va3MgbGlrZS4iIFNwZWNpZmljYWxseSwgdGhpcyBjYXNlIHN0dWR5CndpbGwgY292ZXIgdGhlIGZvbGxvd2luZyB0b3BpY3MgcGVydGFpbmluZyB0byBlYWNoIGRhdGEtaW50ZW5zaXZlCndvcmtmbG93IHByb2Nlc3MgW0BrcnVtbTIwMThdOgoKMS4gICoqUHJlcGFyZSoqOiBQcmlvciB0byBhbmFseXNpcywgd2UnbGwgdGFrZSBhIGxvb2sgYXQgdGhlIGNvbnRleHQKICAgIGZyb20gd2hpY2ggb3VyIGRhdGEgY2FtZSwgZm9ybXVsYXRlIHNvbWUgcmVzZWFyY2ggcXVlc3Rpb25zLCBhbmQgZ2V0CiAgICBpbnRyb2R1Y2VkIHRoZSB7dGlkeWdyYXBofSBhbmQge2dncmFwaH0gcGFja2FnZXMgZm9yIGFuYWx5emluZyBhbmQKICAgIHZpc3VhbGl6aW5nIHJlbGF0aW9uYWwgZGF0YS4KCjIuICAqKldyYW5nbGUqKjogSW4gdGhlIHdyYW5nbGluZyBzZWN0aW9uIG9mIG91ciBjYXNlIHN0dWR5LCB3ZSB3aWxsCiAgICBsZWFybiBzb21lIGJhc2ljIHRlY2huaXF1ZXMgZm9yIG1hbmlwdWxhdGluZywgY2xlYW5pbmcsCiAgICB0cmFuc2Zvcm1pbmcsIGFuZCBtZXJnaW5nIG5ldHdvcmsgZGF0YS4KCjMuICAqKkV4cGxvcmUqKjogV2l0aCBvdXIgbmV0d29yayBkYXRhIHRpZGllZCwgd2UgbGVhcm4gdG8gY2FsY3VsYXRlCiAgICBzb21lIGtleSBuZXR3b3JrIG1lYXN1cmVzIGFuZCB0byBpbGx1c3RyYXRlIHNvbWUgb2YgdGhlc2Ugc3RhdHMKICAgIHRocm91Z2ggbmV0d29yayB2aXN1YWxpemF0aW9uLgoKNC4gICoqTW9kZWwqKjogV2UgY29uY2x1ZGUgb3VyIGFuYWx5c2lzIGJ5IGludHJvZHVjaW5nIGNvbW11bml0eQogICAgZGV0ZWN0aW9uIGFsZ29yaXRobXMgZm9yIGlkZW50aWZ5aW5nIGdyb3VwcyBhbmQgcmV2aXNpdGluZyBzZW50aW1lbnQKICAgIGFib3V0IHRoZSBjb21tb24gY29yZS4KCjUuICAqKkNvbW11bmljYXRlKio6IFdlIGRldmVsb3AgYSBwb2xpc2hlZCBzb2Npb2dyYW0gdG8gaGlnaGxpZ2h0IGtleQogICAgZmluZGluZ3MuCgojIyMgMWEuIFJldmlldyB0aGUgUmVzZWFyY2gKCiFbXShpbWcvcGl0dGluc2t5LWNhcm9sYW4ucG5nKXt3aWR0aD0iNTAlIn0KClBpdHRpbnNreSwgTS4sICYgQ2Fyb2xhbiwgQi4gVi4gKDIwMDgpLiBCZWhhdmlvcmFsIHZlcnN1cyBjb2duaXRpdmUKY2xhc3Nyb29tIGZyaWVuZHNoaXAgbmV0d29ya3MuwqAqU29jaWFsIFBzeWNob2xvZ3kgb2YKRWR1Y2F0aW9uKizCoCoxMSooMiksIDEzMy0xNDcuCgojIyMjIEFic3RyYWN0CgpSZXNlYXJjaGVycyBvZiBzb2NpYWwgbmV0d29ya3MgY29tbW9ubHkgZGlzdGluZ3Vpc2ggYmV0d2VlbiAiYmVoYXZpb3JhbCIKYW5kICJjb2duaXRpdmUiIHNvY2lhbCBzdHJ1Y3R1cmUuIEluIGEgc2Nob29sIGNvbnRleHQsIGZvciBleGFtcGxlLCBhCnRlYWNoZXIncyBwZXJjZXB0aW9ucyBvZiBzdHVkZW50IGZyaWVuZHNoaXAgdGllcywgbm90IG5lY2Vzc2FyaWx5IGFjdHVhbApmcmllbmRzaGlwIHJlbGF0aW9ucywgbWF5IGluZmx1ZW5jZSB0ZWFjaGVyIGJlaGF2aW9yLiBSZXZpc2l0aW5nIGVhcmx5CndvcmsgaW4gdGhlIGZpZWxkIG9mIHNvY2lvbWV0cnksIHRoaXMgc3R1ZHkgYXNzZXNzZXMgdGhlIGxldmVsIG9mCmFncmVlbWVudCBiZXR3ZWVuIHRlYWNoZXIgcGVyY2VwdGlvbnMgYW5kIHN0dWRlbnQgcmVwb3J0cyBvZgp3aXRoaW4tY2xhc3Nyb29tIGZyaWVuZHNoaXAgdGllcy4gVXNpbmcgZGF0YSBmcm9tIG9uZSBtaWRkbGUgc2Nob29sCnRlYWNoZXIgYW5kIGZvdXIgY2xhc3NlcyBvZiBzdHVkZW50cywgdGhlIHN0dWR5IGV4cGxvcmVzIG5ldyBncm91bmQgYnkKYXNzZXNzaW5nIGFncmVlbWVudCBvdmVyIHRpbWUgYW5kIGFjcm9zcyBjbGFzc3Jvb20gc29jaWFsIGNvbnRleHRzLCB3aXRoCnRoZSB0ZWFjaGVyLXBlcmNlaXZlciBoZWxkIGNvbnN0YW50LiBXaGlsZSB0aGUgdGVhY2hlcidzIHBlcmNlcHRpb25zIGFuZApzdHVkZW50cycgcmVwb3J0cyB3ZXJlIHN0YXRpc3RpY2FsbHkgc2ltaWxhciwgMTEtLTI5JSBvZiBwb3NzaWJsZSB0aWVzCmRpZCBub3QgbWF0Y2guIEluIHBhcnRpY3VsYXIsIHN0dWRlbnRzIHJlcG9ydGVkIHNpZ25pZmljYW50bHkgbW9yZQpyZWNpcHJvY2F0ZWQgZnJpZW5kc2hpcCB0aWVzIHRoYW4gdGhlIHRlYWNoZXIgcGVyY2VpdmVkLiBJbnRlcmVzdGluZ2x5LAp0aGUgb2JzZXJ2ZWQgbGV2ZWwgb2YgYWdyZWVtZW50IHZhcmllZCBhY3Jvc3MgY2xhc3NlcyBhbmQgZ2VuZXJhbGx5CmluY3JlYXNlZCBvdmVyIHRpbWUuIFRoaXMgc3R1ZHkgZnVydGhlciBkZW1vbnN0cmF0ZXMgdGhhdCBzaWduaWZpY2FudAplcnJvciBjYW4gYmUgaW50cm9kdWNlZCBieSBjb25mbGF0aW5nIHRlYWNoZXIgcGVyLSBjZXB0aW9ucyBhbmQgc3R1ZGVudApyZXBvcnRzLiBGaW5kaW5ncyByZWluZm9yY2UgdGhlIGltcG9ydGFuY2Ugb2YgdHJlYXRpbmcgYmVoYXZpb3JhbCBhbmQKY29nbml0aXZlIGNsYXNzcm9vbSBmcmllbmRzaGlwIG5ldHdvcmtzIGFzIGRpc3RpbmN0LCBhbmQgYW5hbHl6aW5nCnNvY2lhbCBzdHJ1Y3R1cmUgZGF0YSB0aGF0IGFyZSBjYXJlZnVsbHkgYWxpZ25lZCB3aXRoIHRoZSBzb2NpYWwgcHJvY2VzcwpoeXBvdGhlc2l6ZWQuCgojIyMjIFJlc2VhcmNoIFF1ZXN0aW9ucwoKVGhlIGNlbnRyYWwgcXVlc3Rpb24gZ3VpZGluZyB0aGlzIGludmVzdGlnYXRpb24gd2FzOgoKPiBEbyBzdHVkZW50IHJlcG9ydHMgYWdyZWUgd2l0aCB0ZWFjaGVyIHBlcmNlcHRpb25zIHdoZW4gaXQgY29tZXMgdG8KPiBjbGFzc3Jvb20gZnJpZW5kc2hpcCB0aWVzIGFuZCB3aXRoIHdoYXQgY29uc2VxdWVuY2VzIGZvciBjb21tb25seSB1c2VkCj4gc29jaWFsIG5ldHdvcmsgbWVhc3VyZXM/CgpXZSB3aWxsIGJlIHVzaW5nIHRoaXMgcXVlc3Rpb24gdG8gZ3VpZGUgb3VyIG93biBhbmFseXNpcyBvZiB0aGUKY2xhc3Nyb29tIGZyaWVuZHNoaXBzIHJlcG9ydGVkIGJ5IHRlYWNoZXJzLiBTcGVjaWZpY2FsbHksIHdlIHdpbGwgdXNlCnRoZSBmaXJzdCBwYXJ0IG9mIHRoaXMgcXVlc3Rpb24gdG8gZ3VpZGUgb3VyIGFuYWx5c2lzIGFuZCBkZXZlbG9wIHR3bwpzb2Npb2dyYW1zIHRvIGhlbHAgdmlzdWFsbHkgY29tcGFyZSBzaW1pbGFyaXRpZXMgYW5kIGRpZmZlcmVuY2VzIGJldHdlZW4KdGVhY2hlciBhbmQgc3R1ZGVudCByZXBvcnRlZCBjbGFzc3Jvb20gZnJpZW5kc2hpcHMuCgojIyMjIERhdGEgQ29sbGVjdGlvbgoKVG8gbWVhc3VyZSB0aGUgbGV2ZWwgb2YgYWdyZWVtZW50IGJldHdlZW4gc3R1ZGVudCBhbmQgdGVhY2hlciByZXBvcnRzIG9mCmNsYXNzcm9vbSBzdHVkZW50IGZyaWVuZHNoaXBzLCBzb2Npb21ldHJpYyBkYXRhIHdlcmUgY29sbGVjdGVkIGZyb20gZWFjaApzdHVkZW50IGluIGFsbCBmb3VyIGNsYXNzZXMgYW5kIHRoZSB0ZWFjaGVyIHByb3ZpZGVkIHNpbWlsYXIgcmVwb3J0cyBvbgphbGwgc3R1ZGVudHMuIFRvIGNvbGxlY3Qgc3R1ZGVudCByZXBvcnRzIG9mIGZyaWVuZHNoaXBzLCBzdHVkZW50cyB3ZXJlCmdpdmVuIGEgY2xhc3Mgcm9zdGVyIGFuZCBhc2tlZCB0byBkZXNjcmliZSB0aGVpciByZWxhdGlvbnNoaXAgd2l0aCBlYWNoCnN0dWRlbnQgaW4gdGhlIGNsYXNzLiBDaG9pY2VzIGluY2x1ZGVkIGJlc3QgZnJpZW5kLCBmcmllbmQsIGtub3ctbGlrZSwKa25vdywga25vdy1kaXNsaWtlLCBzdHJvbmdseSBkaXNsaWtlLCBhbmQgZG8gbm90IGtub3cuIEluIHRoZQp0ZXJtaW5vbG9neSBvZiBuZXR3b3JrIGFuYWx5c2lzLCB0aGVzZSBzb2Npb21ldHJpYyBkYXRhIGFyZSAidmFsdWVkIgooZGVncmVlcyBvZiBmcmllbmRzaGlwLCBub3QganVzdCB5ZXMgb3Igbm8pIGFuZCAiZGlyZWN0ZWQiIChmcmllbmRzaGlwCm5vbWluYXRpb25zIHdlcmUgbm90IHByZXN1bWVkIHRvIGJlIHJlY2lwcm9jYWwpLiBEYXRhIHdlcmUgY29sbGVjdGVkIGluCnRoZSBhdXR1bW4gYW5kIHNwcmluZy4gQWxsICJiZXN0IGZyaWVuZCIgYW5kICJmcmllbmQiIGNob2ljZXMgYXJlIGNvZGVkCmFzICcxJyAoZnJpZW5kKSwgd2hpbGUgYWxsIG90aGVyIGNob2ljZXMgYXJlIGNvZGVkIGFzICcwJyAobm90IGZyaWVuZCkuClRoZSB0ZWFjaGVyJ3MgcmVwb3J0cyBvZiBzdHVkZW50cycgZnJpZW5kc2hpcHMgd2VyZSBnZW5lcmF0ZWQgaW4gYQpzaW1pbGFyIG1hbm5lci4KCiMjIyMgQW5hbHlzZXMJCQoKVG8gYXNzZXNzIGFncmVlbWVudCBiZXR3ZWVuIHBlcmNlaXZlZCBmcmllbmRzaGlwIGJ5IHRoZSB0ZWFjaGVyIGFuZApzdHVkZW50cywgUUFQIChxdWFkcmF0aWMgYXNzaWdubWVudCBwcm9jZWR1cmUpIGNvcnJlbGF0aW9ucyBmb3IgZWFjaApjbGFzcydzIHR3byBtYXRyaWNlcyAodGVhY2hlciBhbmQgc3R1ZGVudCBnZW5lcmF0ZWQpIHdlcmUgYW5hbHl6ZWQgaW4KdGhlIGF1dHVtbiBhbmRzcHJpbmcuIEEgUUFQIGNvcnJlbGF0aW9uIGlzIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBkZWdyZWUKb2YgYXNzb2NpYXRpb24gYmV0d2VlbiB0d28gc2V0cyBvZiByZWxhdGlvbnM7IGl0IHRlc3RzIHdoZXRoZXIgdGhlCnByb2JhYmlsaXR5IG9mIGR5YWQgb3ZlcmxhcCBpbiB0aGUgdGVhY2hlciBtYXRyaXggaXMgY29ycmVsYXRlZCB3aXRoIHRoZQpwcm9iYWJpbGl0eSBvZiBkeWFkIG92ZXJsYXAgaW4gdGhlIHN0dWRlbnQgbWF0cml4LiBJdCBkb2VzIHNvIGJ5IHJ1bm5pbmcKYSBsYXJnZSBudW1iZXIgb2Ygc2ltdWxhdGlvbnMuIFRoZXNlIHNpbXVsYXRpb25zIGdlbmVyYXRlIHJhbmRvbQptYXRyaWNlcyB3aXRoIHNpemVzIGFuZCB2YWx1ZSBkaXN0cmlidXRpb25zIGJhc2VkIG9uIHRoZSBvcmlnaW5hbCB0d28KbWF0cmljZXMgYmVpbmcgdGVzdGVkLiBJdCB0aGVuIGNvbXB1dGVzIGFuIGF2ZXJhZ2UgbGV2ZWwgb2YgY29ycmVsYXRpb24KYmV0d2VlbiB0aGUgbWF0cmljZXMgdGhhdCB3b3VsZCBiZSBleHBlY3RlZCBhdCByYW5kb20uIFNpbWlsYXJseSwgaXQKY2FsY3VsYXRlcyB0aGUgcHJvYmFiaWxpdHkgdGhhdCB0aGUgb2JzZXJ2ZWQgZGVncmVlIG9mIGNvcnJlbGF0aW9uCmJldHdlZW4gdHdvIG1hdHJpY2VzIHdvdWxkIGJlIGFzIGxhcmdlIG9yIGFzIHNtYWxsIGFzIHRoYXQgb2JzZXJ2ZWQKYmFzZWQgb24gdGhlIHJhbmdlIG9mIGNvcnJlbGF0aW9ucyBnZW5lcmF0ZWQgaW4gdGhlIHJhbmRvbSBwZXJtdXRhdGlvbnMsCndpdGggYW4gYXNzb2NpYXRlZCBzaWduaWZpY2FuY2Ugc3RhdGlzdGljLgoKIyMjIyBLZXkgRmluZGluZ3MKCkFzIHJlcG9ydGVkIGJ5IEBwaXR0aW5za3kyMDA4YmVoYXZpb3JhbCBpbiB0aGVpciBmaW5kaW5ncyBzZWN0aW9uOgoKPiBXaGlsZSB0aGUgdGVhY2hlcidzIHBlcmNlcHRpb25zIGFuZCBzdHVkZW50cycgcmVwb3J0cyB3ZXJlCj4gc3RhdGlzdGljYWxseSBzaW1pbGFyLCAxMS0tMjklIG9mIHBvc3NpYmxlIHRpZXMgZGlkIG5vdCBtYXRjaC4gSW4KPiBwYXJ0aWN1bGFyLCBzdHVkZW50cyByZXBvcnRlZCBzaWduaWZpY2FudGx5IG1vcmUgcmVjaXByb2NhdGVkCj4gZnJpZW5kc2hpcCB0aWVzIHRoYW4gdGhlIHRlYWNoZXIgcGVyY2VpdmVkLgoKIyMjIyAqKvCfkYkgWW91ciBUdXJuKiogKiripLUqKgoKVGFrZSBhIGxvb2sgYXQgdGhlIHBhcGVyIGluIG91ciBlc3NlbnRpYWwgcmVhZGluZ3MgcmVwb3NpdG9yeSBvbiBHaXRIdWIKYW5kIGhpZ2hsaWdodCBvbmUgb3IgdHdvIGZpbmRpbmdzIGFuZC9vciBjb25jbHVzaW9ucyB5b3UgZm91bmQKZXNwZWNpYWxseSBpbnRlcmVzdGluZy4KCi0gICAKCiMjIyAxYi4gSWRlbnRpZnkgYSBRdWVzdGlvbihzKQoKUmVjYWxsIGZyb20gYWJvdmUgdGhhdCB0aGUgY2VudHJhbCBxdWVzdGlvbiBndWlkaW5nIHRoZSAjQ09NTU9OQ09SRQpQcm9qZWN0IHdhczoKCj4gSG93IGFyZSBzb2NpYWwgbWVkaWEtZW5hYmxlZCBzb2NpYWwgbmV0d29ya3MgY2hhbmdpbmcgdGhlIGRpc2NvdXJzZSBpbgo+IEFtZXJpY2FuIHBvbGl0aWNzIHRoYXQgcHJvZHVjZXMgYW5kIHN1c3RhaW5zIGVkdWNhdGlvbiBwb2xpY3k/CgpGb3IgVW5pdCA0LCB3ZSBhcmUgZ29pbmcgdG8gZm9jdXMgb3VyIHF1ZXN0aW9ucyBvbiBzb21ldGhpbmcgYSBiaXQgbGVzcwphbWJpdGlvdXMgYnV0IGluc3BpcmVkIGJ5IHRoaXMgd29yazoKCjEuICBXaG8gYXJlIHRoZSB0cmFuc21pdHRlcnMsIHRyYW5zY2VpdmVycywgYW5kIHRyYW5zY2VuZGVycyBpbiBvdXIKICAgIENvbW1vbiBDb3JlIFR3aXR0ZXIgbmV0d29yaz8KMi4gIFdoYXQgc3ViZ3JvdXBzLCBvciBmYWN0aW9ucywgZXhpc3QgaW4gb3VyIG5ldHdvcms/CjMuICBXaGljaCBhY3RvcnMgaW4gb3VyIG5ldHdvcmsgdGVuZCB0byBiZSBtb3JlIG9wcG9zZWQgdG8gdGhlIENvbW1vbgogICAgQ29yZT8KClRvIGFkZHJlc3MgdGhlIGxhc3QgcXVlc3Rpb24sIHdlJ2xsIHJldmlzaXQgb3VyIHRlY2huaXF1ZXMgd2UgbGVhcm5lZApmcm9tIG91ciBVbml0IDMgVkFERVIgc2VudGltZW50IGFuYWx5c2lzLgoKIyMjIyAqKvCfkYkgWW91ciBUdXJuKiogKiripLUqKgoKQmFzZWQgb24gd2hhdCB5b3Uga25vdyBhYm91dCBuZXR3b3JrcyBhbmQgdGhlIGNvbnRleHQgc28gZmFyLCB3aGF0IG90aGVyCnJlc2VhcmNoIHF1ZXN0aW9uKHMpIG1pZ2h0IGFzayB3ZSBhc2sgaW4gdGhpcyBjb250ZXh0IHRoYXQgYSBzb2NpYWwKbmV0d29yayBwZXJzcGVjdGl2ZSBtaWdodCBiZSBhYmxlIHRvIGFuc3dlcj8KCkluIHRoZSBzcGFjZSBiZWxvdywgdHlwZSBhIGJyaWVmIHJlc3BvbnNlIHRvIHRoZSBmb2xsb3dpbmcgcXVlc3Rpb25zOgoKLSAgIFlPVVIgUkVTUE9OU0UgSEVSRQoKIyMjIDFjLiBMb2FkIFBhY2thZ2VzCgpBcyBoaWdobGlnaHRlZCBpbsKgW0NoYXB0ZXIgNiBvZiBEYXRhIFNjaWVuY2UgaW4gRWR1Y2F0aW9uIFVzaW5nClJdKGh0dHBzOi8vZGF0YXNjaWVuY2VpbmVkdWNhdGlvbi5jb20vYzA2Lmh0bWwpwqAoRFNJRVVSKSwgb25lIG9mIHRoZQpmaXJzdCBzdGVwcyBvZiBldmVyeSB3b3JrZmxvdyBzaG91bGQgYmUgdG8gc2V0IHVwIHlvdXIgIlByb2plY3QiIHdpdGhpbgpSU3R1ZGlvLiBSZWNhbGwgdGhhdDoKCj4gQSAqKlByb2plY3QqKiBpcyB0aGUgaG9tZSBmb3IgYWxsIG9mIHRoZSBmaWxlcywgaW1hZ2VzLCByZXBvcnRzLCBhbmQKPiBjb2RlIHRoYXQgYXJlIHVzZWQgaW4gYW55IGdpdmVuIHByb2plY3QKClNpbmNlIHdlIGFyZSB3b3JraW5nIGZyb20gYW4gUiBwcm9qZWN0IGNsb25lZCBmcm9tIEdpdEh1YiwgYSBQcm9qZWN0IGhhcwphbHJlYWR5IGJlZW4gc2V0IHVwIGZvciB5b3UgYXMgaW5kaWNhdGVkIGJ5IHRoZSBgLlJwcm9qYCBmaWxlIGluIHlvdXIKbWFpbiBkaXJlY3RvcnkgaW4gdGhlIEZpbGVzIHBhbmUuIEluc3RlYWQsIHdlIHdpbGwgZm9jdXMgb24gZ2V0dGluZyBvdXIKcHJvamVjdCBzZXQgdXAgd2l0aGUgdGhlIHJlcXVpc2l0ZSBwYWNrYWdlcyB3ZSdsbCBuZWVkIGZvciBhbmFseXNpcy4KCioqUGFja2FnZXMqKiwgb3Igc29tZXRpbWVzIGNhbGxlZCBsaWJyYXJpZXMsIGFyZSBzaGFyZWFibGUgY29sbGVjdGlvbnMKb2YgUiBjb2RlIHRoYXQgY2FuIGNvbnRhaW4gZnVuY3Rpb25zLCBkYXRhLCBhbmQvb3IgZG9jdW1lbnRhdGlvbiBhbmQKZXh0ZW5kIHRoZSBmdW5jdGlvbmFsaXR5IG9mIFIuIFlvdSBjYW4gYWx3YXlzIGNoZWNrIHRvIHNlZSB3aGljaApwYWNrYWdlcyBoYXZlIGFscmVhZHkgYmVlbiBpbnN0YWxsZWQgYW5kIGxvYWRlZCBpbnRvIFJTdHVkaW8gQ2xvdWQgYnkKbG9va2luZyBhdCB0aGUgdGhlIEZpbGVzLCBQbG90cywgJiBQYWNrYWdlcyBQYW5lIGluIHRoZSBsb3dlciByaWdodCBoYW5kCmNvcm5lci4KCiMjIyMgdGlkeXZlcnNlIPCfk6YKCiFbXShpbWcvdGlkeXZlcnNlLnBuZyl7d2lkdGg9IjMwJSJ9CgpPbmUgcGFja2FnZSB0aGF0IHdlJ2xsIGJlIHVzaW5nIGV4dGVuc2l2ZWx5IGlzIHt0aWR5dmVyc2V9LiBSZWNhbGwgZnJvbQplYXJsaWVyIHR1dG9yaWFscyB0aGF0IHRoZSB7dGlkeXZlcnNlfSBwYWNrYWdlIGlzIGFjdHVhbGx5IGEgW2NvbGxlY3Rpb24Kb2YgUiBwYWNrYWdlc10oaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy9wYWNrYWdlcykgZGVzaWduZWQgZm9yIHJlYWRpbmcsCndyYW5nbGluZywgYW5kIGV4cGxvcmluZyBkYXRhIGFuZCB3aGljaCBhbGwgc2hhcmUgYW4gdW5kZXJseWluZyBkZXNpZ24KcGhpbG9zb3BoeSwgZ3JhbW1hciwgYW5kIGRhdGEgc3RydWN0dXJlcy4gVGhpcyBzaGFyZWQgZmVhdHVyZXMgYXJlCnNvbWV0aW1lcyAidGlkeSBkYXRhIHByaW5jaXBsZXMuIgoKQ2xpY2sgdGhlIGdyZWVuIGFycm93IGluIHRoZSByaWdodCBjb3JuZXIgb2YgdGhlICJjb2RlIGNodW5rIiB0aGF0CmZvbGxvd3MgdG8gbG9hZCB0aGUge3RpZHl2ZXJzZX0gbGlicmFyeSBhcyB3ZWxsIGFzIHRoZSB7aGVyZX0gcGFja2FnZQppbnRyb2R1Y2VkIGluIHByZXZpb3VzIGxhYnMuCgpgYGB7ciBsb2FkLXRpZHl2ZXJzZX0KbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKRG9uJ3Qgd29ycnkgaWYgeW91IHNhdyBhIG51bWJlciBvZiBtZXNzYWdlczogdGhvc2UgcHJvYmFibHkgbWVhbiB0aGF0CnRoZSB0aWR5dmVyc2UgbG9hZGVkIGp1c3QgZmluZS4gQW55IGNvbmZsaWN0cyB5b3UgbWF5IGhhdmUgc2VlbiBtZWFuCnRoYXQgZnVuY3Rpb25zIGluIHRoZXNlIHBhY2thZ2VzIHlvdSBsb2FkZWQgaGF2ZSB0aGUgc2FtZSBuYW1lIGFzCmZ1bmN0aW9ucyBpbiBvdGhlciBwYWNrYWdlcyBhbmQgUiB3aWxsIGRlZmF1bHQgdG8gZnVuY3Rpb24gZnJvbSB0aGUgbGFzdApsb2FkZWQgcGFja2FnZSB1bmxlc3MKCk5leHQsIHdlIHdpbGwgaW50cm9kdWNlIHR3byBuZXcgcGFja2FnZXMgZXh0ZW5kIHRoZSB0aWR5dmVyc2Ugc3VpdGUgb2YKcGFja2FnZXMgYW5kIHRoYXQgd2Ugd2lsbCB1c2UgdGhyb3VnaG91dCBTTkEgTGVhcm5pbmcgTGFicyAxLTQuCgojIyMgTmV3IFBhY2thZ2VzCgojIyMjIHRpZHlncmFwaCDwn5OmCgohW10oaW1nL3RpZHlncmFwaC5wbmcpe3dpZHRoPSIyMCUifQoKVGhlIHtbdGlkeWdyYXBoXShodHRwczovL3RpZHlncmFwaC5kYXRhLWltYWdpbmlzdC5jb20pfSBwYWNrYWdlIGlzIGEKaHVnZSBwYWNrYWdlIHRoYXQgZXhwb3J0cyAyODAgZGlmZmVyZW50IGZ1bmN0aW9ucyBhbmQgbWV0aG9kcywgaW5jbHVkaW5nCmFjY2VzcyB0byBhbG1vc3QgYWxsIG9mIHRoZcKgYGRwbHlyYMKgdmVyYnMgcGx1cyBhIGZldyBtb3JlLCBkZXZlbG9wZWQgZm9yCnVzZSB3aXRoIHJlbGF0aW9uYWwgZGF0YS4gV2hpbGUgbmV0d29yayBkYXRhIGl0c2VsZiBpcyBub3QgdGlkeSwgaXQgY2FuCmJlIGVudmlzaW9uZWQgYXMgdHdvIHRpZHkgdGFibGVzLCBvbmUgZm9yIG5vZGUgZGF0YSBhbmQgb25lIGZvciBlZGdlCmRhdGEuCgpUaGUge3RpZHlncmFwaH0gcGFja2FnZSBwcm92aWRlcyBhIHdheSB0byBzd2l0Y2ggYmV0d2VlbiB0aGUgdHdvIHRhYmxlcwphbmQgdXNlcyBgZHBseXJgIHZlcmJzIHRvIG1hbmlwdWxhdGUgdGhlbS4gRnVydGhlcm1vcmUgaXQgcHJvdmlkZXMKYWNjZXNzIHRvIGEgbG90IG9mIGdyYXBoIGFsZ29yaXRobXMgd2l0aCByZXR1cm4gdmFsdWVzIHRoYXQgZmFjaWxpdGF0ZQp0aGVpciB1c2UgaW4gYSB0aWR5IHdvcmtmbG93LgoKIyMjIyBnZ3JhcGgg8J+TpgoKIVtdKGltZy9nZ3JhcGgucG5nKXt3aWR0aD0iMjAlIn0KCkNyZWF0ZWQgYnkgdGhlIHNhbWUgZGV2ZWxvcGVyIGFzIHt0aWR5Z3JhcGh9LAp7W2dncmFwaF0oaHR0cHM6Ly9nZ3JhcGguZGF0YS1pbWFnaW5pc3QuY29tL2luZGV4Lmh0bWwpfSAtLSBwcm9ub3VuY2VkCmdnLXJhcGggb3IgZy1naXJhZmZlIGhlbmNlIHRoZSBsb2dvIC0tIGlzIGFuIGV4dGVuc2lvbiBvZgp7W2dncGxvdF0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcpfSBhaW1lZCBhdCBzdXBwb3J0aW5nIHJlbGF0aW9uYWwKZGF0YSBzdHJ1Y3R1cmVzIHN1Y2ggYXMgbmV0d29ya3MsIGdyYXBocywgYW5kIHRyZWVzLiBCb3RoIHBhY2thZ2VzIGFyZQptb3JlIG1vZGVybiBhbmQgd2lkZWx5IGFkb3B0ZWQgYXBwcm9hY2hlcyBkYXRhIHZpc3VhbGl6YXRpb24gaW4gUi4KCldoaWxlIGdncmFwaCBidWlsZHMgdXBvbiB0aGUgZm91bmRhdGlvbiBvZiBnZ3Bsb3QgYW5kIGl0cyBBUEksIGl0IGNvbWVzCndpdGggaXRzIG93biBzZWxmLWNvbnRhaW5lZCBzZXQgb2YgZ2VvbXMsIGZhY2V0cywgZXRjLiwgYXMgd2VsbCBhcwphZGRpbmcgdGhlIGNvbmNlcHQgb2bCoCpsYXlvdXRzKsKgdG8gdGhlIFtncmFtbWFyIG9mCmdyYXBoaWNzXShodHRwczovL2dncGxvdDItYm9vay5vcmcvaW50cm9kdWN0aW9uLmh0bWw/cT1ncmFtbWFyI3doYXQtaXMtdGhlLWdyYW1tYXItb2YtZ3JhcGhpY3MpLAppLmUuIHRoZSAiZ2ciIGluIGdncGxvdCBhbmQgZ2dyYXBoLgoKKipyZWFkeGwg8J+TpioqCgohW10oaW1nL3JlYWR4bC5wbmcpe3dpZHRoPSIyMCUifQoKVGhlwqBbe3JlYWR4bH1dKGh0dHBzOi8vcmVhZHhsLnRpZHl2ZXJzZS5vcmcvKcKgcGFja2FnZSBtYWtlcyBpdCBlYXN5IHRvCmdldCBkYXRhIG91dCBvZiBFeGNlbCBhbmQgaW50byBSLiBDb21wYXJlZCB0byBtYW55IG9mIHRoZSBleGlzdGluZwpwYWNrYWdlcyAoZS5nLsKgZ2RhdGEsIHhsc3gsIHhsc1JlYWRXcml0ZSkgcmVhZHhsIGhhcyBubyBleHRlcm5hbApkZXBlbmRlbmNpZXMsIHNvIGl0J3MgZWFzeSB0byBpbnN0YWxsIGFuZCB1c2Ugb24gYWxsIG9wZXJhdGluZyBzeXN0ZW1zLgpJdCBpcyBkZXNpZ25lZCB0byB3b3JrIHdpdGjCoCp0YWJ1bGFyKsKgZGF0YS4KClNpbmNlIG9uZSBvZiBvdXIgZGF0YSB3cmFuZ2xpbmcgc3RlcHMgaW4gdGhlIG5leHQgc2VjdGlvbiBpcyBpbXBvcnRpbmcKbmV0d29yayBtYXRyaWNlcyBzdG9yZWQgaW4gZXhjZWwgZmlsZXMsIHRoaXMgcGFja2FnZSB3aWxsIGNvbWUgaW4gaGFuZHkuCgojIyMjICoq8J+RiSBZb3VyIFR1cm4qKiAqKuKktSoqCgpVc2UgdGhlIGNvZGUgY2h1bmsgYmVsb3cgbG9hZCB0aGUge3RpZHlncmFwaH0gYW5kIHtnZ3JhcGh9IHBhY2thZ2VzOgoKYGBge3IgbG9hZC1wYWNrYWdlc30KIyBZT1VSIENPREUgSEVSRQpsaWJyYXJ5KHRpZHlncmFwaCkKbGlicmFyeShnZ3JhcGgpCmxpYnJhcnkocmVhZHhsKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgMi4gV1JBTkdMRQoKSW4gZ2VuZXJhbCwgZGF0YSB3cmFuZ2xpbmcgaW52b2x2ZXMgc29tZSBjb21iaW5hdGlvbiBvZiBjbGVhbmluZywKcmVzaGFwaW5nLCB0cmFuc2Zvcm1pbmcsIGFuZCBtZXJnaW5nIGRhdGEgW0B3aWNraGFtMjAxNnJdLiBBcwpoaWdobGlnaHRlZCBpbiBAZXN0cmVsbGFkbzIwMjBlLCB3cmFuZ2xpbmcgbmV0d29yayBkYXRhIGNhbiBiZSBldmVuIG1vcmUKY2hhbGxlbmdpbmcgdGhhbiBvdGhlciBkYXRhIHNvdXJjZXMgc2luY2UgbmV0d29yayBkYXRhIG9mdGVuIGluY2x1ZGVzCnZhcmlhYmxlcyBhYm91dCBib3RoIGluZGl2aWR1YWxzIGFuZCB0aGVpciByZWxhdGlvbnNoaXBzLgoKRm9yIG91ciBkYXRhIHdyYW5nbGluZyBpbiBsYWIsIHdlJ3JlIGtlZXBpbmcgaXQgc2ltcGxlIHNpbmNlIHdvcmtpbmcKd2l0aCByZWxhdGlvbmFsIGRhdGEgaXMgYSBiaXQgb2YgYSBkZXBhcnR1cmUgZnJvbSBvdXIgd29ya2luZyB3aXRoCnJlY3Rhbmd1bGFyIGRhdGEgZnJhbWVzLiBPdXIgcHJpbWFyeSBnb2FscyBmb3IgTGFiIDEgYXJlIGxlYXJuaW5nIGhvdwp0bzoKCmEuICAqKkltcG9ydCBEYXRhKiouIEluIHRoaXMgc2VjdGlvbiwgd2UgbGVhcm4gYWJvdXQgdGhlIGByZWFkX2NzdigpYAogICAgZnVuY3Rpb24gZm9yIGltcG9ydGluZyBhIGRhdGEgc3RvcmVkIGluIGEgZm9ybWF0IGluIGEgdW5pcXVlIHR3bwogICAgY29tbW9uIGZvcm1hdHMgZm9yIHN0b3JpbmcgbmV0d29yayBkYXRhOiBlZGdlbGlzdHMgYW5kIG5vZGVsaXN0cy4KCmIuICAqKkNyZWF0ZSBhIE5ldHdvcmsgT2JqZWN0KiouIEJlZm9yZSB3ZSBjYW4gY3JlYXRlIG91ciBzb2Npb2dyYW0sCiAgICB3ZSdsbCBmaXJzdCBuZWVkIHRvIGNvbnZlcnQgb3VyIGRhdGEgZnJhbWVzIGludG8gc3BlY2lhbCBkYXRhCiAgICBmb3JtYXQsIGFuIFIgbmV0d29yayBvYmplY3QsIGZvciB3b3JraW5nIHdpdGggcmVsYXRpb25hbCBkYXRhLgoKYy4gIAoKIyMjIDJhLiBJbXBvcnQgRGF0YQoKT25lIG9mIG91ciBwcmltYXJ5IGdvYWxzIGZvciB0aGlzIGNhc2Ugc3R1ZHkgdG8gaXMgY3JlYXRlIC4gVG8gZG8gc28sCndlJ2xsIG5lZWQgdG8gaW1wb3J0IHR3byBFeGNlbCBmaWxlcyBvcmlnaW5hbGx5IG9idGFpbmVkIGZyb20KdGhlwqBbU29jaWFsIE5ldHdvcmsgQW5hbHlzaXMgYW5kIEVkdWNhdGlvbiBjb21wYW5pb24Kc2l0ZV0oaHR0cHM6Ly9zdHVkeXNpdGVzLnNhZ2VwdWIuY29tL2Nhcm9sYW4vc3R1ZHkvcmVzb3VyY2VzLmh0bSkuIEJvdGgKZmlsZXMgY29udGFpbiBlZGdlcyBzdG9yZWQgYXMgYSBzcXVhcmUgbWF0cml4IChtb3JlIG9uIHRoaXMgbGF0ZXIpIGZvcgp0aGUgZmlyc3QgYW5kIHRoaXJkIHllYXIgb2YgYSBzdHVkeSBleGFtaW5pbmcgdGhlIGltcGFjdCBvZiBuYXRpb25hbApyZWZvcm0gZWZmb3J0cy4KClRoZXNlIGZpbGVzIGFyZSBpbmNsdWRlZCBpbiB0aGUgbGFiLTEvZGF0YSBmb2xkZXIgb2YgeW91ciBSIFN0dWRpbwpwcm9qZWN0LiBBIGRlc2NyaXB0aW9uIG9mIGVhY2ggZmlsZSBmcm9tIHRoZSBjb21wYW5pb24gd2Vic2l0ZSBpcyBjb3BpZWQKYmVsb3cgYWxvbmcgd2l0aCBhIGxpbmsgdG8gdGhlIG9yaWdpbmFsIGZpbGU6CgoxLiAgWyoqOTk0NzJfZHMzLnhsc3gqKl0oaHR0cHM6Ly9zdHVkeXNpdGVzLnNhZ2VwdWIuY29tL2Nhcm9sYW4vc3R1ZHkvbWF0ZXJpYWxzL2RhdGFzZXRzLzk5NDcyX2RzMy54bHN4KVRoaXMKICAgIGFkamFjZW5jeSBtYXRyaXggY29uc2lzdHMgb2YgKipzdHVkZW50LXJlcG9ydGVkKiogZnJpZW5kc2hpcAogICAgcmVsYXRpb25zIGFtb25nIDI3IHN0dWRlbnRzIGluIG9uZSBjbGFzcyBpbiB0aGUgZmFsbCBzZW1lc3Rlci4gVGhlc2UKICAgIGRhdGEgYXJlIGRpcmVjdGVkIGFuZCB1bndlaWdodGVkOyBhIGZyaWVuZHNoaXAgdGllIGlzIHByZXNlbnQgaWYgdGhlCiAgICBzdHVkZW50IHJlcG9ydGVkIHRoYXQgYW5vdGhlciB3YXMgZWl0aGVyIGEgYmVzdCBmcmllbmQgb3IgZnJpZW5kLgoKMi4gIFsqKjk5NDcyX2RzNS54bHN4KipdKGh0dHBzOi8vc3R1ZHlzaXRlcy5zYWdlcHViLmNvbS9jYXJvbGFuL3N0dWR5L21hdGVyaWFscy9kYXRhc2V0cy85OTQ3Ml9kczUueGxzeClUaGlzCiAgICBhZGphY2VuY3kgbWF0cml4IGNvbnNpc3RzIG9mIHRoZSAqKnRlYWNoZXItcmVwb3J0ZWQqKiBmcmllbmRzaGlwCiAgICByZWxhdGlvbnMgYW1vbmcgMjcgc3R1ZGVudHMgaW4gb25lIGNsYXNzIGluIHRoZSBmYWxsIHNlbWVzdGVyLiBUaGVzZQogICAgZGF0YSBhcmUgZGlyZWN0ZWQgYW5kIHVud2VpZ2h0ZWQ7IGEgZnJpZW5kc2hpcCB0aWUgaXMgcHJlc2VudCBpZiB0aGUKICAgIHRlYWNoZXIgcmVwb3J0ZWQgdGhhdCBzdHVkZW50cyB3ZXJlIGVpdGhlciBhIGJlc3QgZnJpZW5kIG9yIGZyaWVuZC4KClJlY2FsbCBmcm9tIGFib3ZlIHRoYXQgb3VyIHJlbGF0aW9ucywgb3IgZWRnZXMsIGFyZSBzdG9yZWQgYXMgYQp2YWx1ZWTCoFthZGphY2VuY3kKbWF0cml4XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9BZGphY2VuY3lfbWF0cml4KcKgaW4gd2hpY2ggY29sdW1ucwphbmQgcm93cyBjb25zaXN0IG9mIHRoZSBzYW1lIGFjdG9ycyBhbmQgZWFjaCBjZWxsIGNvbnRhaW5zIGluZm9ybWF0aW9uCmFib3V0IHRoZSB0aWUgYmV0d2VlbiBlYWNoIHBhaXIgb2YgYWN0b3JzLiBJbiBvdXIgY2FzZSwgdGhlIHRpZSBpcyBhCmRpcmVjdGVkIGFuZCB2YWx1ZWQgImFyYyIgd2hlcmUgdGhlIHZhbHVlIGluZGljYXRlcyB0aGUgZnJlcXVlbmN5IG9mCmNvbGxhYm9yYXRpb24uCgpMZXQncyB1c2UgdGhlwqBgcmVhZF9leGNlbCgpYMKgZnVuY3Rpb24gdG8gaW1wb3J0CnRoZcKgYHN0dWRlbnQtcmVwb3J0ZWQtZnJpZW5kcy54bHN4YMKgZmlsZSwgYWRkIGFuIGFyZ3VtZW50IHNldHRpbmcgdGhlCmNvbHVtbiBuYW1lcyB0b8KgYEZBTFNFYMKgc2luY2Ugb3VyIGZpbGUgaXMgYSBzaW1wbGUgbWF0cml4IHdpdGggbm8gaGVhZGVyCm9yIGNvbHVtbiBuYW1lcywgYW5kIGFzc2lnbiB0aGUgbWF0cml4IHRvIGEgdmFyaWFibGUKbmFtZWTCoGBzdHVkZW50X2ZyaWVuZHNgOgoKKipSIFN0dWRpbyBUaXA6KirCoFR5cGXCoGA/cmVhZF9leGNlbGDCoGludG8gdGhlIGNvbnNvbGUgYW5kIGNoZWNrIHRoZQphcmd1bWVudHMgc2VjdGlvbiB0byBleGFtaW5lIHRoZSBkaWZmZXJlbnQgYXJndW1lbnRzIHRoYXQgY2FuIGJlIHVzZWQKd2l0aCB0aGlzIGZ1bmN0aW9uLgoKYGBge3Igc3R1ZGVudC1kYXRhfQpzdHVkZW50X2ZyaWVuZHMgPC0gcmVhZF9leGNlbCgiZGF0YS9zdHVkZW50LXJlcG9ydGVkLWZyaWVuZHMueGxzeCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xfbmFtZXMgPSBGQUxTRSkKYGBgCgpCZWZvcmUgaW1wb3J0aW5nIG91ciB0ZWFjaGVyIHJlcG9ydGVkIGZyaWVuZHNoaXAgZmlsZSwgbGV0J3MgcXVpY2tseQppbnNwZWN0IHRoZSBgc3R1ZGVudF9mcmllbmRzYCBSIG9iamVjdCB3ZSBqdXN0IGltcG9ydGVkIHRvIHNlZSB3aGF0CndlJ2xsIGJlIHdvcmtpbmcgd2l0aC4KCmBgYHtyIGluc3BlY3Qtc3R1ZGVudHN9CnN0dWRlbnRfZnJpZW5kcwpgYGAKCkFzIHlvdSBjYW4gc2VlLCB3ZSBoYXZlIGEgMjcgeCAyNwoiW3RpYmJsZV0oaHR0cHM6Ly90aWJibGUudGlkeXZlcnNlLm9yZy8pIiBvciBkYXRhIHRhYmxlIHJlcHJlc2VudGluZyBvdXIKY29sbGFib3JhdGlvbiB0aWVzLiBVbmZvcnR1bmF0ZWx5LCB0aGlzIGRhdGEgaXMgc3RvcmVkIGluIHN1Y2ggYSBzaW1wbGUKZm9ybWF0LCB3ZSBoYXZlIG5vIHdheSB0byBlYXNpbHkgaWRlbnRpZnkgd2hvIGlzIGZyaWVuZHMgd2hvIHNpbmNlIG91cgpkYXRhIGlzIG1pc3NpbmcgbmFtZXMgb3Igc29tZSBraW5kIG9mIGlkZW50aWZpZXIgZm9yIHN0dWRlbnRzIGluIG91cgpuZXR3b3JrLgoKUiBoYXMgcGFja2FnZXMgZm9yIGNyZWF0aW5nIHJhbmRvbSBuYW1lcyB0byBoZWxwIGFub255bWl6ZSBkYXRhLCBidXQgdG8Ka2VlcCB0aGluZ3Mgc2ltcGxlLCB3ZSdsbCBqdXN0IGFzc2lnbiB0aGUgbnVtYmVycyAxLTI3IGFzIG5hbWVzIGZvciBvdXIKcm93cyBhbmQgY29sdW1ucy4KCmBgYHtyIGFzc2lnbi1uYW1lc30Kcm93bmFtZXMoc3R1ZGVudF9mcmllbmRzKSA8LSAxOjI3Cgpjb2xuYW1lcyhzdHVkZW50X2ZyaWVuZHMpIDwtIDE6MjcKYGBgCgpZb3UgbWF5IGhhdmUgc2VlbiBhIHdhcm5pbmcKc3RhdGluZzrCoGBTZXR0aW5nIHJvdyBuYW1lcyBvbiBhIHRpYmJsZSBpcyBkZXByZWNhdGVkLmDCoFlvdSBjYW4gaWdub3JlCnRoYXQgZm9yIG5vdyBidXQgaXQncyBiYXNpY2FsbHkgdGVsbGluZyB1cyB0aGVzZSBmdW5jdGlvbnMgYXJlIG9sZCB3ZSB3ZQpuZWVkIHRvIHVzZSBuZXdlciBmdW5jdGlvbiBvciBvdXIgY29kZSB3aWxsIHNvbWUgZGF5IHN0b3Agd29ya2luZy4KCkFnYWluLCBsZXQgcXVpY2tseSBpbnNwZWN0IG91csKgYHN0dWRlbnRfZnJpZW5kc2AgZGF0YSB0YWJsZSB0byBzZWUgaWYKdGhpcyB3b3JrZWQ6CgpgYGB7ciB2aWV3LXN0dWRlbnRzfQpzdHVkZW50X2ZyaWVuZHMKYGBgCgpNdWNoIGJldHRlciEgTm93IHdlIGNhbiBzZWUgdGhhdCBzdHVkZW50IDEgaW5kaWNhdGVkIHRoYXQgc3R1ZGVudCAyIGlzCnRoZWlyIGZyaWVuZCwgYW4gc3R1ZGVudCAyIGluZGljYXRlZCB0aGF0IHN0dWRlbnQgMSBpcyB0aGVpciBmcmllbmQsIHNvCndlIGNhbiBzYXkgdGhhdCB0aGlzIGZyaWVuZHNoaXAgaXMgInJlY2lwcm9jYXRlZC4iCgojIyMjICoq8J+RiSBZb3VyIFR1cm4qKiAqKuKktSoqCgpDb21wbGV0ZSB0aGUgY29kZSBjaHVuayBiZWxvdyB0byBpbXBvcnQgdGhlCmBzdHVkZW50LXJlcG9ydGVkLWZyaWVuZHMueGxzeGDCoGZpbGUsCgpgYGB7ciBpbXBvcnQtdGVhY2hlcn0KIyBZT1VSIENPREUgSEVSRQp0ZWFjaGVyX2ZyaWVuZHMgPC0gcmVhZF9leGNlbCgiZGF0YS90ZWFjaGVyLXJlcG9ydGVkLWZyaWVuZHMueGxzeCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xfbmFtZXMgPSBGQUxTRSkKCnJvd25hbWVzKHRlYWNoZXJfZnJpZW5kcykgPC0gMToyNwoKY29sbmFtZXModGVhY2hlcl9mcmllbmRzKSA8LSAxOjI3Cgp0ZWFjaGVyX2ZyaWVuZHMKYGBgCgojIyMgMmIuIE1ha2UgYSBUaWR5IEdyYXBoCgpCZWZvcmUgd2UgY2FuIGJlZ2luIGV4cGxvcmluZyBvdXIgZGF0YSB0aHJvdWdoIHRocm91Z2ggbmV0d29yawp2aXN1YWxpemF0aW9uLCB3ZSBtdXN0IGZpcnN0IHJlc3RydWN0dXJlIG91ciAidGliYmxlIiBpbnRvIGEgZm9ybWFsCm1hdHJpeCBvYmplY3QgYW5kIHRoZW4gY29udmVydCB0byBhIG5ldHdvcmsgY2xhc3MgUiBvYmplY3QgcmVxdWlyZWQgYnkKdGhlIHt0aWR5Z3JhcGh9IGFuZCB7Z2dyYXBofSBwYWNrYWdlcy4KCiMjIyMgQ29udmVydCB0byBNYXRyaXgKCk5vdyB0aGF0IHdlIGhhdmUgbmFtZXMgaW5jbHVkZWQgZm9yIG91ciByb3dzIGFuZCBjb2x1bW5zLCB3ZSBuZWVkIHRvCmNvbnZlcnQgb3VyIGRhdGEgdGFibGUsIG9yIHRpYmJsZSwgdG8gYSBmb3JtYWwgbWF0cml4IGNsYXNzIG9iamVjdC4gVG8KZG8gc28gaXMgcmVsYXRpdmVseSBzaW1wbGUgdXNpbmcgdGhlwqBgYXMubWF0cml4KClgwqBmdW5jdGlvbiBidWlsdCBpbnRvClIuCgpgYGB7ciBjb252ZXJ0LW1hdHJpeH0Kc3R1ZGVudF9tYXRyaXggPC0gYXMubWF0cml4KHN0dWRlbnRfZnJpZW5kcykKYGBgCgpUaGUgd29yZCAiY2xhc3MiIGFuZCAib2JqZWN0IiBoYXZlIGJlZW4gdXNlZCBxdWl0ZSBhIGJpdCBpbiB0aGlzCmNhc2Utc3R1ZHkgYW5kIHdhcnJhbnQgYSBicmllZiBleHBsYW5hdGlvbi4gQ2xhc3NlcyBhbmQgb2JqZWN0cyBhcmUKYmFzaWMgY29uY2VwdHMgb2YgT2JqZWN0LU9yaWVudGVkIFByb2dyYW1taW5nIGVudmlyb25tZW50cyBsaWtlIFIuCkFuwqAqKm9iamVjdCoqwqBpcyBzaW1wbHkgYSBkYXRhIHN0cnVjdHVyZSB0aGF0IGhhcyBzb21lIG1ldGhvZHMgYW5kCmF0dHJpYnV0ZXMuIEV2ZXJ5dGhpbmcgaW4gUiBpcyBlc3NlbnRpYWxseSBhbiBvYmplY3QuIEHCoCoqY2xhc3MqKsKgaXMKanVzdCBhIGJsdWVwcmludCBvciBhIHNrZXRjaCBvZiB0aGVzZSBvYmplY3RzLiBJdCByZXByZXNlbnRzIHRoZSBzZXQgb2YKcHJvcGVydGllcyBvciBtZXRob2RzIHRoYXQgYXJlIGNvbW1vbiB0byBhbGwgb2JqZWN0cyBvZiBvbmUgdHlwZS4KCkxldCdzIHVzZSB0aGXCoGBjbGFzcygpYMKgZnVuY3Rpb24gb24gdGhlIGBzdHVkZW50X2ZyaWVuZHNgCmFuZMKgYHN0dWRlbnRfbWF0cml4YMKgdG8gc2VlIHRoZSB0eXBlcyBvZiBvYmplY3RzIHdlIGp1c3QgY3JlYXRlZDoKCmBgYHtyIGNoZWNrLWNsYXNzfQpjbGFzcyhzdHVkZW50X2ZyaWVuZHMpCgpjbGFzcyhzdHVkZW50X21hdHJpeCkKYGBgCgpHcmVhdCEgV2UgY2FuIG5vdyBzZWUgdGhhdCBvdXLCoGBzdHVkZW50X21hdHJpeGDCoGlzIGZvcm1hbGx5IGFuIG9iamVjdCBvZgp0aGUgIm1hdHJpeCIgY2xhc3MuCgojIyMjICoqQ29udmVydCB0byBHcmFwaCBPYmplY3QqKgoKT3VyIGZpbmFsIHN0ZXAgYmVmb3JlIHdlJ3JlIGFibGUgdG8gYmVnaW4gZXhwbG9yaW5nIG91ciBkYXRhIGlzIHRvCmNvbnZlcnQgb3VyIG1hdHJpeCB0byBhIG5ldHdvcmsgb2JqZWN0IHJlY29nbml6ZWQgYnkgdGhlIHt0aWR5Z3JhcGh9IGFuZAp7Z2dyYXBofSBwYWNrYWdlcy4KVGhlwqBbYGFzX3RibF9ncmFwaCgpYF0oaHR0cHM6Ly90aWR5Z3JhcGguZGF0YS1pbWFnaW5pc3QuY29tL3JlZmVyZW5jZS90YmxfZ3JhcGguaHRtbCnCoGZ1bmN0aW9uCmNhbiBlYXNpbHkgY29udmVydCByZWxhdGlvbmFsIGRhdGEgZnJvbSBhbGwgY29tbW9uIG5ldHdvcmsgZGF0YSBmb3JtYXRzCnN1Y2ggYXMgbWF0cmljZXMsIGBuZXR3b3JrYCwgYHBoeWxvYCwgYGRlbmRyb2dyYW1gLCBgZGF0YS50cmVlYCwKYGdyYXBoYCwgZXRjLsKgCgpSdW4gdGhlIGZvbGxvd2luZyBjb2RlIHRvIGNvbnZlcnQgb3VyIG1hdHJpeCB0byBkaXJlY3RlZCBuZXR3b3JrIGdyYXBoCmFuZCBzYXZlIGFzIGEgbmV3IG9iamVjdCBjYWxsZWTCoGBzdHVkZW50X25ldHdvcmtgOiBhbmQgaW5jbHVkZSB0aGUKYXJndW1lbnQgYGRpcmVjdGVkID0gVFJVRWAgaW4gb3VyIGBhc190YmxfZ3JhcGgoKWAgZnVuY3Rpb24gc2luY2Ugb3VyCm5ldHdvcmsgaXMgZGlyZWN0ZWQuCgpgYGB7ciBjb252ZXJ0LW5ldHdvcmt9CnN0dWRlbnRfbmV0d29yayA8LSBhc190YmxfZ3JhcGgoc3R1ZGVudF9tYXRyaXgsIGRpcmVjdGVkID0gVFJVRSkKYGBgCgpOb3cgbGV0J3MgdGFrZSBhIHF1aWNrIGxvb2sgYXQgb3VyIG5ldyBgc3R1ZGVudF9uZXR3b3JrYCBvYmplY3Q6CgpgYGB7ciBzdHVkZW50LW5ldHdvcmt9CnN0dWRlbnRfbmV0d29yawpgYGAKCkFzIHlvdSBjYW4gc2VlLCBvdXLCoGBzdHVkZW50X25ldHdvcmtgIG9iamVjdCBwcm92aWRlcyBhIHJhbmdlIG9mCmluZm9ybWF0aW9uIGFib3V0IG91dCBuZXR3b3JrIGluY2x1ZGluZyBuZXR3b3JrIHNpemUsIHR5cGUsIG51bWJlciBvZgpjb21wb25lbnRzLCBhbmQgYSBwcmV2aWV3IG9mIHRoZSBub2RlIGFuZCBlZGdlIGxpc3RzIHRoYXQgaXQgY3JlYXRlZC4KVGhlIG5vZGUgYW5kIGVkZ2UgbGlzdHMgYXJlIHRyZWF0ZWQganVzdCBsaWtlIGEgdHlwaWNhbCBkYXRhIGZyYW1lIGFuZApjYW4gbm93IGJlIHVzZWQgd2l0aCBvdGhlciB0aWR5dmVyc2UgcGFja2FnZXMgYW5kIGZ1bmN0aW9ucyB0byBjcmVhdGUKbmV3IGFjdG9yLWxldmVsIG5ldHdvcmsgdmFyaWFibGVzIGxpa2UgZGVncmVlLCByZWNpcHJvY2l0eSwgYW5kCmNlbnRyYWxpdHkgbWVhc3VyZXMuCgojIyMjIFdoYXQgaXMgYW4gZWRnZSBsaXN0PyAKCldlJ2xsIGxlYXJuIG1vcmUgYWJvdXQgZWRnZWxpc3RzIGluIExhYiAzLCBidXQgdGhlICoqZWRnZWxpc3QqKiBmb3JtYXQKaXMgdmVyeSBjb21tb25seSB1c2VkIGluIG5ldHdvcmsgYW5hbHlzaXMgYnV0IGlzIHNsaWdodGx5IGRpZmZlcmVudCB0aGFuCm90aGVyIGZvcm1hdHMgeW91IGhhdmUgbGlrZWx5IHdvcmtlZCB3aXRoIGJlZm9yZS4gU3BlY2lmaWNhbGx5LCB0aGUKdmFsdWVzIGluIHRoZSBmaXJzdCB0d28gY29sdW1ucyBvZiBlYWNoIHJvdyByZXByZXNlbnQgYSBkeWFkLCBvciB0aWUKYmV0d2VlbiB0d28gbm9kZXMgaW4gYSBuZXR3b3JrLiBBbiBlZGdlLWxpc3QgY2FuIGFsc28gY29udGFpbiBvdGhlcgppbmZvcm1hdGlvbiByZWdhcmRpbmcgdGhlIHN0cmVuZ3RoLCBkdXJhdGlvbiwgb3IgZnJlcXVlbmN5IG9mIHRoZQpyZWxhdGlvbnNoaXAsIHNvbWV0aW1lIGNhbGxlZCAqKndlaWdodCoqLCBpbiBhZGRpdGlvbiB0byBvdGhlciAiZWRnZQphdHRyaWJ1dGVzLiIKCkluIGRpcmVjdGVkIG5ldHdvcmtzIGxpa2Ugb3VycywgdGhlIGZpcnN0IGNvbHVtbiBpbmRpY2F0ZXMgdGhhdCBzdHVkZW50CjEgaW5kaWNhdGVkIHN0dWRlbnRzIDIsIDQsIGFuZCA1IGFyZSBmcmllbmRzLiBTaW5jZSBvdXIgbmV0d29yayBpcwp1bndlaWdodGVkLCB0aGUgMSBmb3IgIndlaWdodCIganVzdCBpbmRpY2F0ZWQgdGhhdCBhIGZyaWVuZHNoaXAgd2FzCnByZXNlbnQuCgojIyMjICoq8J+RiSBZb3VyIFR1cm4qKiAqKuKktSoqCgpDb21wbGV0ZSB0aGUgY29kZSBjaHVuayBiZWxvdyB0byBjb252ZXJ0IHlvdXIgYHRlYWNoZXJfZnJpZW5kc2Agb2JqZWN0CmZpcnN0IHRvIGEgbWF0cml4IGFuZCB0aGVuIHRvIGEgbmV0d29yayBvYmplY3Q6CgpgYGB7cn0KIyBZT1VSIENPREUgSEVSRQp0ZWFjaGVyX21hdHJpeCA8LSBhcy5tYXRyaXgodGVhY2hlcl9mcmllbmRzKQoKdGVhY2hlcl9uZXR3b3JrIDwtIGFzX3RibF9ncmFwaCh0ZWFjaGVyX21hdHJpeCwgZGlyZWN0ZWQgPSBUUlVFKQoKdGVhY2hlcl9uZXR3b3JrCmBgYAoKTm93IGFuc3dlciB0aGUgcXVlc3Rpb25zIHRoYXQgZm9sbG93aW5nIHF1ZXN0aW9uczoKCjEuICBIb3cgbWFueSBzdHVkZW50cyBhcmUgaW4gb3VyIG5ldHdvcms/CiAgICAtICAgWU9VUiBSRVNQT05TRSBIRVJFCjIuICBXaG8gcmVwb3J0ZWQgbW9yZSBmcmllbmRzaGlwcywgdGVhY2hlcnMgb3Igc3R1ZGVudHM/IEhvdyBkbyB5b3UKICAgIGtub3c/CiAgICAtICAgWU9VUiBSRVNQT05TRSBIRVJFCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIDMuIEVYUExPUkUKCkFzIG5vdGVkIGluIGluIG91ciBjb3Vyc2UgcmVhZGluZ3MsIGV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMgaW52b2x2ZXMKdGhlIHByb2Nlc3NlcyBvZiBkZXNjcmliaW5nIHlvdXIgZGF0YSAoc3VjaCBhcyBieSBjYWxjdWxhdGluZyB0aGUgbWVhbnMKYW5kIHN0YW5kYXJkIGRldmlhdGlvbnMgb2YgbnVtZXJpYyB2YXJpYWJsZXMsIG9yIGNvdW50aW5nIHRoZSBmcmVxdWVuY3kKb2YgY2F0ZWdvcmljYWwgdmFyaWFibGVzKSBhbmQsIG9mdGVuLCB2aXN1YWxpemluZyB5b3VyIGRhdGEgcHJpb3IgdG8KbW9kZWxpbmcuCgpJbiBTZWN0aW9uIDMsIHdlIHVzZSB0aGUge3RpZHlncmFwaH0gcGFja2FnZSBmb3IgcmV0cmlldmluZyBuZXR3b3JrCmRlc2NyaXB0aXZlcyBhbmQgaW50cm9kdWNlIHRoZSB7Z2dyYXBofSBwYWNrYWdlIHRvIGNyZWF0ZSBhIG5ldHdvcmsKdmlzdWFsaXphdGlvbiB0byBoZWxwIGlsbHVzdHJhdGUgdGhlc2UgbWV0cmljcy4gU3BlY2lmaWNhbGx5LCBpbiB0aGlzCnNlY3Rpb24gd2UnbGwgbGVhcm4gdG86CgphLiAgKipQbG90IEJhc2ljcyoqLiBXZSBmb2N1cyBwcmltYXJpbHkgb24gYWN0b3JzIGFuZCBlZGdlcyBpbiB0aGlzCiAgICB3YWxrdGhyb3VnaCwgaW5jbHVkaW5nIHRoZSBlZGdlcyB3aWdodHMgd2UgYWRkZWQgaW4gdGhlIHByZXZpb3VzCiAgICBzZWN0aW9uIGFzIHdlbGwgYXMgbm9kZSBkZWdyZWUsIGFuZCBpbXBvcnQgYW5kIGZhaXJseSBpbnR1aXRpdmUKICAgIG1lYXN1cmUgb2YgY2VudHJhbGl0eS4KCmIuICBBZGRpbmcgTm9kZXMuCgpjLiAgKipBZGRpbmcgRWRnZXMqKi4gRmluYWxseSwgd2Ugd3JhcCB1cCB0aGUgZXhwbG9yZSBwaGFzZXMgYnkgbGVhcm5pbmcKICAgIHRvIHBsb3QgYSBuZXR3b3JrIGFuZCB0d2VhayBrZXkgZWxlbWVudHMgbGlrZSB0aGUgc2l6ZSwgc2hhcGUsIGFuZAogICAgcG9zaXRpb24gb2Ygbm9kZXMgYW5kIGVkZ2VzIHRvIGJldHRlciBhdCBjb21tdW5pY2F0aW5nIGtleSBmaW5kaW5ncy4KCk9uZSBvZiB0aGUgZGVmaW5pbmcgY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSBzb2NpYWwgbmV0d29yayBwZXJzcGVjdGl2ZSBpcwppdHMgdXNlIG9mIGdyYXBoaWMgaW1hZ2VyeSB0byByZXByZXNlbnQgYWN0b3JzIGFuZCB0aGVpciByZWxhdGlvbnMgd2l0aApvbmUgYW5vdGhlci4gVG8gZW1waGFzaXplIHRoaXMgcG9pbnQsIEBjYXJvbGFuMjAxNCByZXBvcnRlZCB0aGF0OgoKPiBUaGUgdmlzdWFsaXphdGlvbiBvZiBzb2NpYWwgbmV0d29ya3MgaGFzIGJlZW4gYSBjb3JlIHByYWN0aWNlIHNpbmNlCj4gaXRzIGZvdW5kYXRpb24gbW9yZSB0aGFuIDEwMCB5ZWFycyBhZ28gYW5kIHJlbWFpbnMgYSBoYWxsbWFyayBvZgo+IGNvbnRlbXBvcmFyeSBzb2NpYWwgbmV0d29yayBhbmFseXNpcy7CoAoKTmV0d29yayB2aXN1YWxpemF0aW9uIGNhbiBiZSB1c2VkIGZvciBhIHZhcmlldHkgb2YgcHVycG9zZXMsIHJhbmdpbmcKZnJvbSBoaWdobGlnaHRpbmcga2V5IGFjdG9ycyB0byBldmVuIHNlcnZpbmcgYXMgd29ya3Mgb2YgYXJ0LgoKVGhpcyBleGNlbGxlbnQgZmlndXJlIGZyb20gS2F0eWEgT2dueWFub3ZhJ3MgYWxzbyBleGNlbGxlbnQgdHV0b3JpYWwgb24KW1N0YXRpYyBhbmQgRHluYW1pYyBOZXR3b3JrIFZpc3VhbGl6YXRpb24gd2l0aApSXShodHRwczovL2thdGV0by5uZXQvbmV0d29yay12aXN1YWxpemF0aW9uLykgaGVscHMgaWxsdXN0cmF0ZSB0aGUKdmFyaWV0eSBvZiBnb2FscyBhIGdvb2QgbmV0d29yayB2aXN1YWxpemF0aW9uIGNhbiBhY2NvbXBsaXNoOgoKIVtdKGltZy92aXotZ29hbHMuanBlZyl7d2lkdGg9IjgwJSJ9CgojIyMgM2EuIFNpbXBsZSBTb2Npb2dyYW1zIAoKVGhlc2UgdmlzdWFsIHJlcHJlc2VudGF0aW9ucyBvZiB0aGUgYWN0b3JzIGFuZCB0aGVpciByZWxhdGlvbnMsIGkuZS4gdGhlCm5ldHdvcmssIGFyZSBjYWxsZWQgYSAqKnNvY2lvZ3JhbSoqLiBBY3RvcnMgd2hvIGFyZSBtb3N0IGNlbnRyYWwgdG8gdGhlCm5ldHdvcmssIHN1Y2ggYXMgdGhvc2Ugd2l0aCBoaWdoZXIgbm9kZSBkZWdyZWVzLCBhcmUgdXN1YWxseSBwbGFjZWQgaW4KdGhlIGNlbnRlciBvZiB0aGUgc29jaW9ncmFtIGFuZCB0aGVpciB0aWVzIGFyZSBwbGFjZWQgbmVhciB0aGVtLiBBcwp3ZSdsbCBzZWUgaW4ganVzdCBhIGJpdCwgdGhvc2UgdHdvIGFjdG9ycyB3aXRoIGh1bmRyZWRzIG9mIHRpZXMgd2lsbCBiZQpwbGFjZWQgYnkgbW9zdCBncmFwaCBsYXlvdXQgYWxnb3JpdGhtcyBpbiB0aGUgY2VudGVyIG9mIHRoZSBncmFwaC4KClRoZSBgcGxvdCgpYCBmdW5jdGlvbiBmcm9tIFIncyBidWlsdCBpbiB7Z3JhcGhpY3N9IHBhY2thZ2UgY2FuIGJlIHVzZWQKdG8gbWFrZSBhIHdpZGUgcmFuZ2Ugb2YgZ3JhcGhzLCBpbmNsdWRpbmcgc29jaW9ncmFtcywgYnV0IGFzIHlvdSdsbCBzZWUKaXQncyBhIGJpdCBsYWNraW5nIGFuZCBpcyBsaW1pdGVkIGxpbWl0ZWQgaW4gdGhlIGxldmVsIG9mIGN1c3RvbWl6YXRpb24KYWxsb3dlZC4KCkluIHRoZSBjb2RlIGNodW5rIGJlbG93LCB1c2UgdGhlIGBwbG90KClgIGZ1bmN0aW9uIHdpdGggeW91cgpgY2Nzc19uZXR3b3JrYCBvYmplY3QgdG8gc2VlIHdoYXQgdGhlIGJhc2ljIHBsb3QgZnVuY3Rpb24gcHJvZHVjZXM6CgpgYGB7ciBwbG90LW5ldHdvcmt9CnBsb3Qoc3R1ZGVudF9uZXR3b3JrKQpgYGAKCk5vdCBzdXBlciBncmVhdC4gSW4gZmFjdCwgaXQncyB2aXN1YWxpemF0aW9ucyBsaWtlIHRoZXNlIHRoYXQgZ2l2ZQpzb2Npb2dyYW1zIHRoZSB1bmZsYXR0ZXJpbmcgbmlja25hbWUgb2YgImhhaXIgYmFsbCIgcGxvdHMhCgpJZiB0aGlzIGhhZCBiZWVuIGEgc21hbGxlciBuZXR3b3JrIHRoaXMgbWlnaHQgaGF2ZSBiZWVuIGEgbGl0dGxlIG1vcmUKdXNlZnVsIGJ1dCBvbmUgaW1wb3J0YW50IGluc2lnaHQgaXMgdGhhdCB3ZSBoYXZlIGFscmVhZHkgaWRlbnRpZmllZCBhbgoiaXNvbGF0ZSIgaW4gb3VyIG5ldHdvcmssIHRoYXQgaXMgYSBzdHVkZW50IHdobyBuZWl0aGVyIG5hbWVkIG90aGVycyBhcwphIGZyaWVuZCBvciB3YXMgbmFtZWQgYnkgb3RoZXJzIGFzIGEgZnJpZW5kLgoKRm9ydHVuYXRlbHksIHRoZSB7Z2dyYXBofSBwYWNrYWdlIGluY2x1ZGVzIGEgcGxldGhvcmEgb2YgcGxvdHRpbmcKcGFyYW1ldGVycyBmb3IgZ3JhcGgKW2xheW91dHNdKGh0dHBzOi8vZ2dyYXBoLmRhdGEtaW1hZ2luaXN0LmNvbS9hcnRpY2xlcy9MYXlvdXRzLmh0bWwpLApbZWRnZXNdKGh0dHBzOi8vZ2dyYXBoLmRhdGEtaW1hZ2luaXN0LmNvbS9hcnRpY2xlcy9FZGdlcy5odG1sKSBhbmQKW25vZGVzXShodHRwczovL2dncmFwaC5kYXRhLWltYWdpbmlzdC5jb20vYXJ0aWNsZXMvTm9kZXMuaHRtbCkgdG8KaW1wcm92ZSB0aGUgdmlzdWFsIGRlc2lnbiBvZiBuZXR3b3JrIGdyYXBocy4KCkxldCdzIGZpcnN0IHRha2UgYSBxdWljayBsb29rIHRoZSBgYXV0b19ncmFwaCgpYCBmdW5jdGlvbiBmb3IgbWFraW5nCnF1aWNrIGFuZCBzaW1wbGUgc29jaW9ncmFtcy4KCmBgYHtyIGF1dG8tZ3JhcGh9CmF1dG9ncmFwaChzdHVkZW50X25ldHdvcmspCmBgYAoKQSBsaXR0bGUgYmV0dGVyLCBidXQgYWxzbyBsYWNraW5nIGluIG1hbnkgaW1wb3J0YW50IHdheXMuIExpa2UgdGhlCmBwbG90KClgIGZ1bmN0aW9uLCBpdCBkb2VzIGFsbG93IHNvbWUgc21hbGwgZGVncmVlIG9mIGN1c3RvbWl6YXRpb24sIGJ1dAppcyBzdGlsbCByYXRoZXIgbGltaXRlZCBhbmQgYmVzdCB1c2UgZm9yIHZlcnkgcXVpY2sgc29jaW9ncmFtcyB0byBnZXQgYQpxdWljayBmZWVsIGZvciB0aGUgZGF0YS4KClJ1biB0aGUgZm9sbG93aW5nIGNvZGUgY2h1bmsgdG8gc2VlIHNvbWUgYWRkaXRpb25hbCBhcmd1bWVudHMgeW91IGNhbgphZGQgdG8gdGhlIGBhdXRvZ3JhcGgoKWAgZnVuY3Rpb246CgpgYGB7ciBzdHVkZW50LXNvY2lvZ3JhbX0KYXV0b2dyYXBoKHN0dWRlbnRfbmV0d29yaywKICAgICAgICAgIG5vZGVfc2l6ZSA9IGxvY2FsX3NpemUoKSwKICAgICAgICAgIG5vZGVfbGFiZWwgPSBuYW1lLAogICAgICAgICAgbm9kZV9jb2xvdXIgPSBsb2NhbF9zaXplKCkpCmBgYAoKIyMjIyAqKvCfkYkgWW91ciBUdXJuKiogKiripLUqKgoKVXNlIHRoZSBjb2RlIGNodW5rIGJlbG93IHRvIHRyeSBvdXQgdGhlc2Ugc2ltcGxlIHNvY2lvZ3JhbSBmdW5jdGlvbnMgb24KeW91ciBgdGVhY2hlcl9uZXR3b3JrYCBvYmplY3QgeW91IGNyZWF0ZWQgYWJvdmU6CgpgYGB7ciB0ZWFjaGVyLXNvY2lvZ3JhbX0KIyBZT1VSIENPREUgSEVSRQpwbG90KHRlYWNoZXJfbmV0d29yaykKCmF1dG9ncmFwaCh0ZWFjaGVyX25ldHdvcmssCiAgICAgICAgICBub2RlX3NpemUgPSBsb2NhbF9zaXplKCksCiAgICAgICAgICBub2RlX2NvbG91ciA9IGxvY2FsX3NpemUoKSkKYGBgCgojIyMgM2IuIFNvcGhpc3RpY2F0ZWQgU29jaW9ncmFtcwoKT25lIHRoaW5nIHRvIGtlZXAgaW4gbWluZCB3aGVuIGJ1aWxkaW5nIGEgbmV0d29yayB2aXogd2l0aCB7Z2dyYXBofSwgaXMKdGhhdCBqdXN0IGxpa2UgaXQncyBgZ2dwbG90KClgIGNvdW50ZXJwYXJ0LCB0aGUgYGdncmFwaCgpYCBmdW5jdGlvbiBpcwp0aGUgZmlyc3QgZnVuY3Rpb24gcmVxdWlyZWQgYW5kIHRha2VzIGNhcmUgb2Ygc2V0dGluZyB1cCB0aGUgcGxvdCBvYmplY3QKYWxvbmcgd2l0aCBjcmVhdGluZyB0aGUgbGF5b3V0IGZvciB0aGUgcGxvdCBiYXNlZCBvbiB0aGUgbmV0d29yayBvYmplY3QKYW5kIHRoZSBsYXlvdXQgc3BlY2lmaWNhdGlvbiBwcm92aWRlZC4KCkxldCdzIGZpcnN0IHBhc3Mgb3VyIGBzdHVkZW50X25ldHdvcmtgIG9iamVjdCB0byBgZ2dyYXBoKClgIGFuZCBzZWUgd2hhdApoYXBwZW5zLgoKYGBge3J9CmdncmFwaChzdHVkZW50X25ldHdvcmspCmBgYAoKV293LCB0aGF0IHdhcyB1bmltcHJlc3NpdmUuIEJ1dCBkb24ndCB3b3JyeSwganVzdCBsaWtlIHRoZSBgZ2dwbG90KClgCmZ1bmN0aW9uLCB0aGlzIGRpZG4ndCBwcm9kdWNlIG11Y2ggb24gaXQncyBvd24uIEFsbCB0aGF0IHRoZSBgZ2dyYXBoKClgCmZ1bmN0aW9uIGRvZXMgaXMgc2V0IHVwIHRoZSBuZXR3b3JrIG9iamVjdCB0byBtYWtlIGEgc29jaW9ncmFtLCBhbmQKY3JlYXRlcyBhIGxheW91dCBmb3Igb3VyIG5ldHdvcmssIGluIHRoaXMgY2FzZSB1c2luZyB0aGUgZGVmYXVsdAoic3RyZXNzIiBsYXlvdXQuCgojIyMjIEFkZCBOb2RlcwoKVmVyeSBzaW1pbGFyIHRvIGhvdyBgZ2dwbG90KClgIHVzZXMgdGhlIGArYCBvcGVyYXRvciB0byAibGF5ZXIiCmZ1bmN0aW9ucyB0b2dldGhlciB0byBwcm9ncmVzc2l2ZWx5IGJ1aWxkIG1vcmUgc29waGlzdGljYXRlZCBncmFwaHMsCmBnZ3JhcGhgIHVzZSB0aGUgYCtgIG9wZXJhdG9yIHByb2dyZXNzaXZlbHkgYnVpbGQgYSBzb2Npb2dyYW0uCgpUbyBhZGQgb3VyIG5vZGVzLCB3ZSdsbCBhZGRlZCB0aGUgYGdlb21fbm9kZV9wb2ludCgpYCBmdW5jdGlvbi4gQWdhaW4sCmp1c3QgbGlrZSB3aXRoIHtnZ3Bsb3QyfSwgdGhlICJnZW9tIiBpbiB0aGUgYGdlb21fbm9uX3BvaW50KClgIGZ1bmN0aW9ucwpzdGFuZHMgZm9yICJHZW9tZXRyaWMgZWxlbWVudHMiLCBvciBnZW9tcyBmb3Igc2hvcnQsIGFuZCByZXByZXNlbnRzIHdoYXQKeW91IGFjdHVhbGx5IHNlZSBpbiB0aGUgcGxvdC4KCiMjIyMgKirwn5GJIFlvdXIgVHVybioqICoq4qS1KioKCk5vdyAiYWRkIiB0aGUgYGdlb21fbm9kZV9wb2ludCgpYCBmdW5jdGlvbiB0byBvdXIgY29kZSB1c2luZyB0aGUgYCtgCm9wZXJhdG9yOgoKYGBge3J9CmdncmFwaChzdHVkZW50X25ldHdvcmspICsgCiAgZ2VvbV9ub2RlX3BvaW50KCkgCmBgYAoKV2VsbCwgYXQgbGVhc3Qgd2UgaGF2ZSBvdXIgbm9kZXMgbm93ISBCdXQgdGhlIGRlZmF1bHQgInN0cmVzcyIgbGF5b3V0CmZvciBvdXIgc29jaW9ncmFtIGlzIG5vdCBzbyBncmVhdC4gTGV0J3MgZml4IHRoYXQuCgojIyMjIEFkZCBMYXlvdXQKCk9uZSBvZiB0aGUgbWFqb3IgYWR2YW5jZXMgaW4gdmlzdWFsaXphdGlvbiBzaW5jZSB0aGUgZmlyc3QgaGFuZC1kcmF3bgpzb2Npb2dyYW1zIGRldmVsb3BlZCBieSBKYWNvYiBNb3Jlbm8gKDE5MzQpIHRvIHJlcHJlc2VudCByZWxhdGlvbnMgYW1vbmcKY2hpbGRyZW4gaW4gc2Nob29sIGlzIHRoZSB1c2Ugb2Ygc29mdHdhcmUgYW5kIGFsZ29yaXRobXMgdG8KYXV0b21hdGljYWxseSBsYXlvdXQgbmV0d29ya3Mgb24gYSBncmlkLgoKVGhlcmUgYXJlIG1heSBkaWZmZXJlbnQgW2xheW91dAptZXRob2RzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9HcmFwaF9kcmF3aW5nI0xheW91dF9tZXRob2RzKSwKYnV0IHdlJ2xsIHN0YXJ0IHdpdGggdGhlIEZydWNodGVybWFuLVJlaW5nb2xkIChGUikgbGF5b3V0LCB3aGljaCBpcyBvbmUKb2YgdGhlIG1vc3QgdXNlZCBsYXlvdXQgYWxnb3JpdGhtcyBmb3IgbmV0d29yayB2aXN1YWxpemF0aW9uLiBUaGVzZQp0eXBlcyBvZiBmb3JjZS1kaXJlY3RlZCBhbGdvcml0aG1zIGdlbmVyYWxseSB3b3JrIHdlbGwgd2l0aCBsYXJnZQpuZXR3b3JrcyBhbmQgdHJ5IHRvIGxheW91dCBncmFwaHMgaW4gImFuIGFlc3RoZXRpY2FsbHktcGxlYXNpbmcgd2F5IiBieQptYWtpbmcgZWRnZXMgcm91Z2hseSBlcXVhbCBpbiBsZW5ndGggYW5kIG1pbmltaXppbmcgb3ZlcmxhcC4KCkxldCdzIGdvIGFoZWFkIGFuZCBpbmNsdWRlIHRoZSBsYXlvdXQgYXJndW1lbnQsIHdoaWNoIGluIGFkZGl0aW9uIHRvCmluY2x1ZGluZyBpdHMgb3duIHVuaXF1ZSBsYXlvdXRzLCBjYW4gaW5jb3Jwb3JhdGUgbGF5b3V0cyBmb3JtIHtpZ3JhcGh9CnBhY2thZ2UgbGlrZSBgZnJgIGZvciB0aGUgRnJ1Y2h0ZXJtYW4tUmVpbmdvbGQgKEZSKSBsYXlvdXQ6CgpgYGB7cn0KZ2dyYXBoKHN0dWRlbnRfbmV0d29yaywgbGF5b3V0ID0gImZyIikgKwogIGdlb21fbm9kZV9wb2ludCgpCmBgYAoKVGhhdCdzIG5vdCBtdWNoIGJldHRlciBzbyBsZXQncyBzdGljayB3aXRoIHRoZSAic3RyZXNzIiBsYXlvdXQgZm9yIG5vdy4KRmVlbCBmcmVlIHRvIHRyeSBvdXQgc29tZSBvdGhlciBbZ2dyYXBoIGxheW91dAptZXRob2RzXShodHRwczovL2dncmFwaC5kYXRhLWltYWdpbmlzdC5jb20vYXJ0aWNsZXMvTGF5b3V0cy5odG1sKSBpZiB5b3UKbGlrZSwgaG93ZXZlci4KCiMjIyMgVHdlYWsgTm9kZXMKCkFsc28gbGlrZSB7Z2dwbG90Mn0sIGdlb21zIGNhbiBpbmNsdWRlIGFlc3RoZXRpY3MsIG9yIGFlcyBmb3Igc2hvcnQsCnN1Y2ggYXMgYGFscGhhYCBmb3IgdHJhbnNwYXJlbmN5LCBhcyB3ZWxsIGFzIGBjb2xvcmAsIGBzaGFwZWAgYW5kCmBzaXplYC4KCkxldCdzIG5vdyBhZGQgc29tZSAiYWVzdGhldGljcyIgdG8gb3VyIHBvaW50cyBieSBpbmNsdWRpbmcgdGhlIGBhZXMoKWAKZnVuY3Rpb24gYW5kIGFyZ3VtZW50cyBzdWNoIGFzIGBzaXplID1gIGFuZCBgY29sb3IgPWAsIHdoaWNoIHNldCB1c2luZwpgbG9jYWxfc2l6ZSgpYCBmdW5jdGlvbiB0byBoZWxwIGhpZ2hsaWdodCB0aGUgbnVtYmVyIG9mIGZyaWVuZHMgc3R1ZGVudHMKaGF2ZToKCmBgYHtyIGFkZC1jb2xvcn0KZ2dyYXBoKHN0dWRlbnRfbmV0d29yaywgbGF5b3V0ID0gInN0cmVzcyIpICsgCmdlb21fbm9kZV9wb2ludChhZXMoc2l6ZSA9IGxvY2FsX3NpemUoKSwKICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGxvY2FsX3NpemUoKSkpCmBgYAoKV2UgY2FuIGVhc2lseSBzZWUgdGhhdCB0aGUgbnVtYmVyIG9mIGZyaWVuZHMgcmFuZ2VzIGZyb20gNSB0byAyMCwgd2l0aAp0aGUgZXhjZXB0aW9uIG9mIG9uZSAiaXNvbGF0ZWQiIHN0dWRlbnQgd2UgaWRlbnRpZmllZCBlYXJsaWVyIHdobyBpcyBub3QKY29ubmVjdGVkIHRvIGFueSBvdGhlciBzdHVkZW50cyBpbiB0aGUgbmV0d29yay4KCkxldCdzIGZpeCB0aGF0IGJ5IGFkZGluZyBhbm90aGVyIGxheWVyIHdpdGggc29tZSBub2RlIHRleHQgYW5kIGxhYmVscy4KU2luY2Ugbm9kZSBsYWJlbHMgYXJlIGEgZ2VvbWV0cmljIGVsZW1lbnQsIHdlIGNhbiBhcHBseSBhZXN0aGV0aWNzIHRvCnRoZW0gYXMgd2VsbCwgbGlrZSBjb2xvciBhbmQgc2l6ZS4gTGV0J3MgYWxzbyBpbmNsdWRlIHRoZSBgcmVwZWwgPWAKYXJndW1lbnQgdGhhdCB3aGVuIHNldCB0b8KgYFRSVUVgwqB3aWxsIGF2b2lkIG92ZXJsYXBwaW5nIHRleHQuCgpgYGB7ciBhZGQtbGFiZWxzfQpnZ3JhcGgoc3R1ZGVudF9uZXR3b3JrLCBsYXlvdXQgPSAic3RyZXNzIikgKyAKICBnZW9tX25vZGVfcG9pbnQoYWVzKHNpemUgPSBsb2NhbF9zaXplKCksCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGxvY2FsX3NpemUoKSkpICsKICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lLAogICAgICAgICAgICAgICAgICAgICBzaXplID0gbG9jYWxfc2l6ZSgpKSwgIyBub3RlIHdlIGNhbiB0cmVhdCB0aGlzIGxpa2UgYSBudW1iZXIKICAgICAgICAgICAgICAgICByZXBlbD1UUlVFKQpgYGAKCiMjIyMgQWRkIEVkZ2VzCgpOb3csIGxldCdzIGxpdGVyYWxseSBjb25uZWN0IHRoZSBkb3RzIGFuZCBhZGQgc29tZQpbZWRnZXNdKGh0dHBzOi8vZ2dyYXBoLmRhdGEtaW1hZ2luaXN0LmNvbS9hcnRpY2xlcy9FZGdlcy5odG1sKSB1c2luZyB0aGUKYGdlb21fZWRnZV9saW5rKClgIGZ1bmN0aW9uLgoKYGBge3J9CmdncmFwaChzdHVkZW50X25ldHdvcmssIGxheW91dCA9ICJzdHJlc3MiKSArIAogIGdlb21fbm9kZV9wb2ludChhZXMoc2l6ZSA9IGxvY2FsX3NpemUoKSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gbG9jYWxfc2l6ZSgpKSkgKwogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLAogICAgICAgICAgICAgICAgIHJlcGVsPVRSVUUpICsKICBnZW9tX2VkZ2VfbGluaygpCmBgYAoKQWNrISBXaXRob3V0IHNvbWUgYWRqdXN0bWVudCwgdGhlIGVkZ2VzIG1ha2UgaXQgcmVhbGx5IGRpZmZpY3VsdCB0byBzZWUKdGhlIG5vZGVzLiBGb3J0dW5hdGVseSwgeW91IGNhbiBhbHNvIGFkanVzdCB0aGUgZWRnZXMganVzdCBsaWtlIHdlIGRpZAp0byB0aGUgbm9kZXMgYWJvdmU6IExldCdzIG5vdyBpbmNsdWRlIHRoZSBmb2xsb3dpbmcgYXJndW1lbnRzOgoKLSAgIGBhcnJvdyA9YCB0byBpbmNsdWRlIHNvbWUgYXJyb3dzIDFtbSBpbiBsZW5ndGgKCi0gICBgZW5kX2NhcCA9YCBhcm91bmQgZWFjaCBub2RlIHRvIGtlZXAgYXJyb3dzIGZyb20gb3ZlcmxhcHBpbmcgdGhlCiAgICB0aGVtLCBhbmQgdG8KCi0gICBgYWxwaGEgPSAuMmAgc2V0IHRoZSB0cmFuc3BhcmVuY3kgb2Ygb3VyIGVkZ2VzIHNvIG91ciBlZGdlcyBmYWRlCiAgICBtb3JlIGludG8gdGhlIGJhY2tncm91bmQgYW5kIGhlbHAga2VlcCB0aGUgZm9jdXMgb24gb3VyIG5vZGVzOgoKYGBge3IgdHdlYWstZWRnZXN9CmdncmFwaChzdHVkZW50X25ldHdvcmssIGxheW91dCA9ICJzdHJlc3MiKSArIAogIGdlb21fbm9kZV9wb2ludChhZXMoc2l6ZSA9IGxvY2FsX3NpemUoKSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gbG9jYWxfc2l6ZSgpKSkgKwogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLAogICAgICAgICAgICAgICAgIHJlcGVsPVRSVUUpICsKICBnZW9tX2VkZ2VfbGluayhhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMSwgJ21tJykpLCAKICAgICAgICAgICAgICAgICBlbmRfY2FwID0gY2lyY2xlKDMsICdtbScpLAogICAgICAgICAgICAgICAgIGFscGhhID0gLjIpCmBgYAoKIyMjIyBBZGQgYSBUaGVtZQoKRmluYWxseSwgbGV0J3MgYWRkIGEgKip0aGVtZSwqKiB3aGljaCBjb250cm9scyB0aGUgZmluZXIgcG9pbnRzIG9mCmRpc3BsYXksIGxpa2UgdGhlIGZvbnQgc2l6ZSBhbmQgYmFja2dyb3VuZCBjb2xvci4gVGhlIGB0aGVtZV9ncmFwaCgpYApmdW5jdGlvbiBhZGQgYSB0aGVtZSBzcGVjaWFsbHkgdHVuZWQgZm9yIGdyYXBoIHZpc3VhbGl6YXRpb25zLiBUaGlzCmZ1bmN0aW9uIHJlbW92ZXMgcmVkdW5kYW50IGVsZW1lbnRzIGluIG9yZGVyIHRvIHB1dCBmb2N1cyBvbiB0aGUgZGF0YQphbmQgaWYgeW91IHR5cGUgYD90aGVtZV9ncmFwaGAgaW4gdGhlIGNvbnNvbGUgeW91IHdpbGwgZ2V0IGEgc2Vuc2Ugb2YKdGhlIGxldmVsIG9mIGZpbmUgdHVuaW5nIHlvdSBjYW4gZG8gaWYgZGVzaXJlZC4KCkxldCdzIGFkZCBgdGhlbWVfZ3JhcGgoKWAgdG8gb3VyIHNvY2lvZ3JhbSwgcmVtb3ZlIHRoZSBsZWdlbmRzIHNpbmNlCnRoZXkgYXJlIG5vdCBlc3BlY2lhbGx5IHVzZWZ1bCwgYW5kIGNhbGwgaXQgZ29vZCBmb3Igbm93OgoKYGBge3IgYWRkLXRoZW1lfQpnZ3JhcGgoc3R1ZGVudF9uZXR3b3JrLCBsYXlvdXQgPSAic3RyZXNzIikgKyAKICBnZW9tX25vZGVfcG9pbnQoYWVzKHNpemUgPSBsb2NhbF9zaXplKCksCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGxvY2FsX3NpemUoKSkpICsKICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwKICAgICAgICAgICAgICAgICByZXBlbD1UUlVFKSArCiAgZ2VvbV9lZGdlX2xpbmsoYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDEsICdtbScpKSwgCiAgICAgICAgICAgICAgICAgZW5kX2NhcCA9IGNpcmNsZSgzLCAnbW0nKSwKICAgICAgICAgICAgICAgICBhbHBoYSA9IC4yKSArCiAgdGhlbWVfZ3JhcGgoKQpgYGAKCk11Y2ggYmV0dGVyIQoKKipOb3RlOioqIElmIHlvdSdyZSBoYXZpbmcgZGlmZmljdWx0eSBzZWVpbmcgdGhlIHNvY2lvZ3JhbSBpbiB0aGUgc21hbGwKUiBNYXJrZG93biBjb2RlIGNodW5rLCB5b3UgY2FuIGNvcHkgYW5kIHBhc3RlIHRoZSBjb2RlIGluIHRoZSBjb25zb2xlCmFuZCBpdCB3aWxsIHNob3cgaW4gdGhlIFZpZXdlciBwYW4gYW5kIHRoZW4geW91IGNhbiBlbmxhcmdlIGFuZCBldmVuCnNhdmUgYXMgYW4gaW1hZ2UgZmlsZS4KCiMjIyMgKirwn5GJIFlvdXIgVHVybioqICoq4qS1KioKCk5vdyB0aGF0IHlvdSBoYXZlIGEgc2Vuc2Ugb2YgaG93IHRoZSB7Z2dyYXBofSBwYWNrYWdlIHdvcmtzIHRvIGJ1aWxkCm5ldHdvcmsgZ3JhcGhzLCB1c2UgdGhlIGNvZGUgY2h1bmsgYmVsb3cgYW5kIHRyeSBidWlsZGluZyBzb3BoaXN0aWNhdGVkCnNvY2lvZ3JhbSBmb3IgdGhlIGB0ZWFjaGVyX25ldHdvcmtgIG9iamVjdCB0aGF0IHlvdSBjcmVhdGVkIGFib3ZlLgoKVGhlcmUgYXJlIG5vIHJpZ2h0IG9yIHdyb25nIGFuc3dlcnMsIGp1c3QgaGF2ZSBzb21lIGZ1biB0cnlpbmcgb3V0CmRpZmZlcmVudCBvcHRpb25zIGZvciBncmFwaApbbGF5b3V0c10oaHR0cHM6Ly9nZ3JhcGguZGF0YS1pbWFnaW5pc3QuY29tL2FydGljbGVzL0xheW91dHMuaHRtbCksCltlZGdlc10oaHR0cHM6Ly9nZ3JhcGguZGF0YS1pbWFnaW5pc3QuY29tL2FydGljbGVzL0VkZ2VzLmh0bWwpIGFuZApbbm9kZXNdKGh0dHBzOi8vZ2dyYXBoLmRhdGEtaW1hZ2luaXN0LmNvbS9hcnRpY2xlcy9Ob2Rlcy5odG1sKSBhbmQgc2VlCmlmIHlvdSBjYW4gYnVpbGQgc29tZXRoaW5nIHRoYXQgaXMgdmlzdWFsbHkgcGxlYXNpbmcgdG8geW91LgoKYGBge3IgeW91ci1zb2Npb2dyYW19CmdncmFwaCh0ZWFjaGVyX25ldHdvcmssIGxheW91dCA9ICJmciIpICsgCiAgZ2VvbV9ub2RlX3BvaW50KGFlcyhzaXplID0gbG9jYWxfc2l6ZSgpLAogICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBsb2NhbF9zaXplKCkpKSArCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksCiAgICAgICAgICAgICAgICAgcmVwZWw9VFJVRSkgKwogIGdlb21fZWRnZV9saW5rKGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgxLCAnbW0nKSksIAogICAgICAgICAgICAgICAgIGVuZF9jYXAgPSBjaXJjbGUoMywgJ21tJyksCiAgICAgICAgICAgICAgICAgYWxwaGEgPSAuMikgKwogIHRoZW1lX2dyYXBoKCkKYGBgCgpDb25ncmF0cyEgWW91IG1hZGUgaXQgdG8gdGhlIGVuZCBvZiB0aGUgRVhQTE9SRSBzZWN0aW9uIQoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyA0LiBNT0RFTAoKQXMgaGlnaGxpZ2h0ZWQgaW7CoFtDaGFwdGVyIDMgb2YgRGF0YSBTY2llbmNlIGluIEVkdWNhdGlvbiBVc2luZwpSXShodHRwczovL2RhdGFzY2llbmNlaW5lZHVjYXRpb24uY29tL2MwMy5odG1sKSwgdGhlwqAqKk1vZGVsKirCoHN0ZXAgb2YKdGhlIGRhdGEgc2NpZW5jZSBwcm9jZXNzIGVudGFpbHMgInVzaW5nIHN0YXRpc3RpY2FsIG1vZGVscywgZnJvbSBzaW1wbGUKdG8gY29tcGxleCwgdG8gdW5kZXJzdGFuZCB0cmVuZHMgYW5kIHBhdHRlcm5zIGluIHRoZSBkYXRhLiIgV2Ugd2lsbCBub3QKZXhwbG9yZSB0aGUgdXNlIG9mIG1vZGVscyBmb3IgU05BIHVudGlsIExhYiA0LCBidXQgcmVjYWxsIGZyb20gdGhlClBSRVBBUkUgc2VjdGlvbiB0aGF0IHRvIGFzc2VzcyBhZ3JlZW1lbnQgYmV0d2VlbiBwZXJjZWl2ZWQgZnJpZW5kc2hpcHMKYnkgdGhlIHRlYWNoZXIgYW5kIHN0dWRlbnRzLCBbQHBpdHRpbnNreTIwMDhiZWhhdmlvcmFsXSBub3RlIHRoYXQ6Cgo+ICoqVGhlIFFBUCAocXVhZHJhdGljIGFzc2lnbm1lbnQgcHJvY2VkdXJlKSoqIFtpc10gdXNlZCB0byBjYWxjdWxhdGUKPiB0aGUgZGVncmVlIG9mIGFzc29jaWF0aW9uIGJldHdlZW4gdHdvIHNldHMgb2YgcmVsYXRpb25zIGFuZCB0ZXN0cwo+IHdoZXRoZXIgdGhlIHByb2JhYmlsaXR5IG9mIGR5YWQgb3ZlcmxhcCBpbiB0aGUgdGVhY2hlciBtYXRyaXggaXMKPiBjb3JyZWxhdGVkIHdpdGggdGhlIHByb2JhYmlsaXR5IG9mIGR5YWQgb3ZlcmxhcCBpbiB0aGUgc3R1ZGVudCBtYXRyaXguCj4gSXQgZG9lcyBzbyBieSBydW5uaW5nIGEgbGFyZ2UgbnVtYmVyIG9mIHNpbXVsYXRpb25zLiBUaGVzZSBzaW11bGF0aW9ucwo+IGdlbmVyYXRlIHJhbmRvbSBtYXRyaWNlcyB3aXRoIHNpemVzIGFuZCB2YWx1ZSBkaXN0cmlidXRpb25zIGJhc2VkIG9uCj4gdGhlIG9yaWdpbmFsIHR3byBtYXRyaWNlcyBiZWluZyB0ZXN0ZWQuCgpXZSB3aWxsIGxlYXJuIG1vcmUgYWJvdXQgdGhlIFFBUCBhbmQgb3RoZXIgbW9kZWxzIGZvciBzdGF0aXN0aWNhbAppbmZlcmVuY2Ugd2hlbiB3b3JraW5nIHdpdGggcmVsYXRpb25hbCBkYXRhIGluIExlYXJuaW5nIExhYiA0LgoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyA1LiBDT01NVU5JQ0FURQoKT3VyIGdvYWwgaXMgdG8gZGlzdGlsbCB0aGUgYW5hbHlzaXMgZnJvbSBhYm92ZSBpbnRvIGEgc2ltcGxlICJkYXRhCnByb2R1Y3QiIGRlc2lnbmVkIHRvIGlsbHVzdHJhdGUga2V5IGZpbmRpbmdzIGFib3V0IGNoYW5nZXMgaW4gdGhlCmNvbGxhYm9yYXRpb24gbmV0d29yayBvdmVyIHRpbWUuIEZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyB0YXNrLCBpbWFnaW5lCnRoYXQgeW91ciBhdWRpZW5jZSBjb25zaXN0cyBvZiB0ZWFjaGVycyBhbmQgc2Nob29sIGxlYWRlcnMgd2hvIGhhdmUKbGltaXRlZCBiYWNrZ3JvdW5kIGluIFNOQSBhbmQgYWRhcHQgdGhlIGZvbGxvd2luZyBzdGVwcyBhY2NvcmRpbmdseToKCjEuICAqKlNlbGVjdC4qKiBTZWxlY3Qgb3VyIHNvY2lvZ3JhbSBmcm9tIGFib3ZlLCBvciBjcmVhdGUgYSBlbnRpcmVseQogICAgbmV3IHNvY2lvZ3JhbSBpZiBzbyBtb3RpdmF0ZWQsIHRoYXQgeW91IHRoaW5rIHdvdWxkIGJlIGludGVyZXN0aW5nCiAgICBvciByZWxldmFudCBmb3IgdGhlIHRhcmdldCBhdWRpZW5jZSBhbmQgdGhhdCBoZWxwcyBhbnN3ZXIgb3VyCiAgICByZXNlYXJjaCBxdWVzdGlvbi4KCjIuICAqKlBvbGlzaC4qKiBDcmVhdGUgYSB2aXN1YWxseSBhdHRyYWN0aXZlIHNvY2lvZ3JhbSB0byBoZWxwCiAgICBpbGx1c3RyYXRlIHNpbWlsYXJpdGllcyBhbmQgZGlmZmVyZW5jZXMgaW4gY2xhc3Nyb29tIGZyaWVuZHNoaXBzCiAgICByZXBvcnRlZCBieSB0ZWFjaGVycyBhbmQgc3R1ZGVudHMuCgozLiAgKipOYXJyYXRlLioqIFdyaXRlIGEgYnJpZWYgbmFycmF0aXZlIHRvIGFjY29tcGFueSB5b3VyIHZpc3VhbGl6YXRpb24KICAgIGFuZC9vciB0YWJsZSB0aGF0IGluY2x1ZGVzIHRoZSBmb2xsb3dpbmc6CgogICAgLSAgIFRoZSBxdWVzdGlvbiBvciBxdWVzdGlvbnMgZ3VpZGluZyB0aGUgYW5hbHlzaXM7CgogICAgLSAgIFRoZSBjb25jbHVzaW9ucyB5b3UndmUgcmVhY2hlZCBiYXNlZCBvbiBvdXIgZmluZGluZ3M7CgogICAgLSAgIEhvdyB5b3VyIGF1ZGllbmNlIG1pZ2h0IHVzZSB0aGlzIGluZm9ybWF0aW9uOwoKICAgIC0gICBIb3cgeW91IG1pZ2h0IHJldmlzaXQgb3IgaW1wcm92ZSB1cG9uIHRoaXMgYW5hbHlzaXMgaW4gdGhlCiAgICAgICAgZnV0dXJlLgoKIyMjIPCfkYkgWW91ciBUdXJuIOKktQoKVXNlIHRoZSBjb2RlIGNodW5rIGJlbG93IGNyZWF0ZSBhIHBvbGlzaGVkIHRhYmxlIGFuZC9vciB2aXN1YWxpemF0aW9uKHMpCmFuZCB3cml0ZSBhIGJyaWVmIG5hcnJhdGl2ZSBpbiB0aGUgc3BhY2UgdGhhdCBmb2xsb3dzLgoKIyMjIERhdGEgVmlzdWFsaXphdGlvbiBvciBUYWJsZQoKYGBge3IgY3JlYXRlX2RhdGFfcHJvZHVjdH0KIyBZT1VSIENPREUgSEVSRQoKCmBgYAoKIyMjIE5hcnJhdGl2ZQoKTkFSUkFUSVZFIEdPRVMgSEVSRS4uLgoKIyMjIPCfp7YgS25pdCAmIENoZWNrIOKchQoKQ29uZ3JhdHVsYXRpb25zIC0geW91J3ZlIGNvbXBsZXRlZCB0aGUgTGFiIDQgY2FzZSBzdHVkeSEgT25lIGZpbmFsIHN0ZXAKaXMgdG8gIktuaXQiIHlvdXIgZG9jdW1lbnQgYnkgY2xpY2tpbmcgdGhlIGRyb3AgZG93biBhcnJvdyBuZXh0IHRvIHRoZQpiYWxsIG9mIHlhcm4gaW4gdGhlIG1lbnUgYmFyIGFuIHRoYXQgdGhlIHRvcCBvZiB0aGlzIG1hcmtkb3duIGZpbGUsIGFuZAp0aGVuIHNlbGVjdGluZyAiS25pdCB0b3AgSFRNTCIgb3IgYW5vdGhlciBwcmVmZXJyZWQgb3V0cHV0IGZvcm1hdC4gVGhpcwp3aWxsIGRvIHR3byB0aGluZ3M6IDEpIGl0IHdpbGwgY2hlY2sgdGhyb3VnaCBhbGwgeW91ciBjb2RlIGZvciBhbnkKZXJyb3JzLCAyKSBpdCB3aWxsIGNyZWF0ZWQgYSBmaWxlIGluIHlvdXIgZGlyZWN0b3J5IHRoYXQgeW91IGNhbiB1c2UgdG8Kc2hhcmUgeW91IHdvcmsgdGhyb3VnaCBbR2l0SHViIFBhZ2VzXShodHRwczovL3BhZ2VzLmdpdGh1Yi5jb20pLApbUlB1YnNdKGh0dHBzOi8vcnB1YnMuY29tL2Fib3V0L2dldHRpbmctc3RhcnRlZCksIG9yIGFueSBvdGhlciBwcmVmZXJyZWQKbWVhbnMuCgojIyMgUmVmZXJlbmNlcwo=